Device Client Library User Guide¶
The Python device client libraries simplify working with the Oracle IoT Cloud Service. These client libraries are a higher-level abstraction of messages and REST APIs. Device clients are designed to make it easy to expose device functionality to the Oracle IoT Cloud Service.
The true state of a device is within the device itself (whether the light is on or off). A “virtual” device object is contained within the cloud. The device clients can represent the last-known state of that device, and allow enterprise clients to send commands and set attributes of the device model (e.g., “turn the light off”).
Configuration¶
The client must have a runtime configuration in order to communicate with the cloud service. This runtime configuration includes the IoT Cloud Service host, the identifier of the device the client represents, and the shared secret of the device.
The configuration is created by registering a device with the Oracle IoT Cloud Service and downloading the provisioning file. The downloaded file is encrypted and used when running the client application.
The library defines a set of tunable parameters that affects the library
behavior dealing with messages, network, and other library features.
See config
Device Models¶
A device model is a predefined specification of the attributes, actions, formats and resources of a device that can be accessed by the client library. The attributes of a device model represent the basic variables that the device supports, such as temperature, humidity, flow rate, valve position, and so forth. Actions are similar to attributes, but are invocable state rather than readable state. For example, “reset”. An action can have one or zero arguments. The formats of a device model define the structure of a message payload. A format describes the message attributes by specifying the attribute names, types, optionality, and default values. The resources of a device model define additional, ad-hoc REST resources which provide richer REST support than what is possible with attributes and formats.
The client library has explicit API for obtaining a device model. See
iotcs.client.Client.getDeviceModel()
By default the API above always uses the network to retrieve a given device
model. This behavior can be changed to cache device models to a local file
store by setting a property in the configuration module config
config.ini file. Set the value of the property device_model_store
in the
section device_model
, to an existing, local file directory.
Each model will be stored in its own file using a pattern of
dm-{URL encoded device model URN}.json
, for example
dm-urn%3Acom%3Aoracle%3Aiot%3Adevice%3Ahumidity_sensor.json
.
Statically provisioning a local file directory with device models avoids
network traffic; however, the local model must be identical to the model on the
server. Dynamic provisioning, in which the client library retrieves the model
from the server, ensures correctness of the model, but at the expense of
network traffic. Dynamic provisioning is recommended.
Beware that when using a local store of device models, a local model will not get updated if the model on the server is changed.
Device Policies¶
A policy is a set of rules and constraints that can be associated with a device
client (see below) to control its basic data transformation and transfer
behavior. Device policies are automatically loaded, if they have been
configured for the device, and there is no direct API in the library for
manipulating the policies. The policies are applied when a value is offered to
a VirtualDevice. See VirtualDevice.offer()
Device Client¶
There is an API for getting and setting values on a physical device,
represented by a VirtualDevice
.
A device client application creates a DirectlyConnectedDevice
or
a GatewayDevice
. The application uses the Oracle IoT Client API
to create instances of a “virtual device” VirtualDevice
which
provides access to the device, to get and set values. Further detail is
available in the Client
documentation.
Prerequisites¶
- Register your device application with the Cloud Service.
- Download the provisioning file after registration. Record the passphrase used to encrypt the provisioning file for later use.
- Optionally provision the device model.
Loggers¶
The available loggers
- iotcs.activation.ActivationManager
- iotcs.client.attributes.VirtualDeviceAttributeImpl
- iotcs.client.DeviceModelFactory
- iotcs.client.device.AlertMessageImpl
- iotcs.client.device.DataImpl
- iotcs.client.device.DirectlyConnectedDevice
- iotcs.client.device.StorageObjectImpl._ProgressCallback
- iotcs.client.device.VirtualDeviceImpl.ErrorCallbackBridge
- iotcs.client.device.VirtualDeviceImpl.errorNotifyThread
- iotcs.device.impl.VirtualDeviceImpl
- iotcs.device.impl.MessageDispatcherImpl
- iotcs.device.impl.MessageDispatcherImpl.Dispatcher
- iotcs.device.impl.MessageDispatcherImpl.Receiver
- iotcs.device.impl.MessageDispatcherImpl.Transmitter
- iotcs.device.impl.SendReceiveImpl
- iotcs.diagnostics.Diagnostics
- iotcs.diagnostics.TestConnectivity.TestConnectivityThread
- iotcs.http.HttpSecureConnection
- iotcs.http.HttpSendReceiveImpl
- iotcs.message.DataMessage
- iotcs.messaging.client.storage.StorageConnectionBase
- iotcs.messaging.client.device.persistence
- iotcs.messaging.client.device.persistence.BatchByPersistence
- iotcs.messaging.client.device.persistence.MessagePersistence
- iotcs.messaging.client.device.DirectlyConnectedDeviceImpl
- iotcs.messaging.client.device.util.RequestDispatcher
- iotcs.messaging.client.device.DeviceAnalogImpl
- iotcs.messaging.client.device.MessagingPolicy
- iotcs.messaging.client.device.ScheduledPolicyData
- iotcs.messaging.client.device.TimedPolicyThread
- iotcs.messaging.client.device.storage.StorageDispatcherImpl.ContentTransmitter
- iotcs.shared.RequestBuffer
Directly Connected Device Client Quick Start¶
The following steps must be performed by a device client application to allow a device to be monitored and controlled.
Initialize a device client
DirectlyConnectedDevice
, ensure that theconfigurationFilePath
is not pointing to a read only file as this might be modified during activationfrom iotcs.client.DirectlyConnectedDevice import DirectylyConnectedDevice ... dcd = DirectlyConnectedDevice(configurationFilePath, passphrase)
Activate the device, where
deviceModelUrn
is the urn identifying the device model, for exampleurn:com:oracle:iot:device:humidity_sensor
.if not dcd.isActivated(): dcd.activate([deviceModelUrn])
Obtain the device model
DeviceModel
wheredeviceModelUrn
is the urn identifying the device model, for exampleurn:com:oracle:iot:device:humidity_sensor
.# The type returned by ``getDeviceModel`` from iotcs.client.DeviceModel import DeviceModel ... deviceModel = dcd.getDeviceModel(deviceModelUrn)
Create a virtual device
VirtualDevice
implementing the device model# The type returned by "createVirtualDevice" from iotcs.client.device.VirtualDevice import VirtualDevice ... virtualDevice = dcd.createVirtualDevice(dcd.getEndpointId(), deviceModel)
Listen for control operations using callbacks
ChangeCallback
,Callable
, from an enterprise client. Also implement anErrorCallback
# The VirtualDevice type from iotcs.client.VirtualDevice import VirtualDevice # Implement a ChangeCallback handler class OnChangeCallback(VirtualDevice.ChangeCallback): __slots__ = ( 'realdevice' ) __init__(self, realdevice): super(OnChangeCallback, self).__init__() # # provide any custom initialization or context to # reference when the "onChange" method is called # self.realdevice = realdevice def onChange(self, event): # Get the virtual device if needed virtualdevice = event.getVirtualDevice() namedvalue = event.getNamedValue() while namedValue is not None: attribute = namedvalue.getName() value = namedvalue.getValue() # # update the device with the new value # # handle multiple attribute updates self.realdevice[attribute] = value namedvalue = namedValue.next() # set the callback for any changes from the server to this virtualobject virtualdevice.setOnChange(OnChangeCallback()) # Implement a Callable handler for a "reset" action class Reset(VirtualDevice.Callable): __slots__ = ( 'realdevice' ) __init__(self, realdevice): super(Rest, self).__init__() # # provide any custom initialization or context to # reference when the "call" method is called # self.realdevice = realdevice def call(self): # # perform the reset action # self.realdevice.reset() # Set a handler for a callable action. For example, the device model # might have a 'reset' action. In this example, the action does not # require any input data. virtualdevice.setCallable("reset", Reset(theactualdevice)) # Implement a Callable handler for a "calibrate" action class Calibrate(VirtualDevice.Callable): __slots__ = ( 'realdevice' ) __init__(self, realdevice): super(Calibrate, self).__init__() # # provide any custom initialization or context to # reference when the "call" method is called # self.realdevice = realdevice def call(self, zerooffset): # # calibrate the device to 'zerooffset' # self.realdevice.calibrate(zerooffset) # Set a handler for a callable action. For example, the device model # might have a 'calibrate' action. In this example, the action # requires numeric input data. virtualdevice.setCallable("calibrate", Calibrate(theactualdevice)) # Implement an ErrorCallback handler class OnErrorCallback(VirtualDevice.ErrorCallback): __slots__ = ( 'realdevice' ) __init__(self, realdevice): super(OnErrorCallback, self).__init__() # # provide any custom initialization or context to # reference when the "call" method is called # self.realdevice = realdevice def onError(self, errorevent): # log the error logging.getLogger("onError").warn(errorevent.getMessage()) # Get the virtual device if needed virtualdevice = event.getVirtualDevice() namedvalue = event.getNamedValue() while namedValue is not None: attribute = namedvalue.getName() value = namedvalue.getValue() # # do anything to the real device if necessary # # handle multiple attribute updates namedvalue = namedValue.next() self.realdevice.reboot() # set a callback to receive errors from sending data to the server virtualdevice.setOnError(OnErrorCallback())
Update the virtual device when the data on the physical device changes
# set a value for a particular attribute in this virtual device virtualdevice.set("attribute", newValue); // or set multiple attributes in a batch operation virtualdevice.update() .set("attribute1", value1) .set("attribute2", value2) .finish()
Dispose of the device client
dcd.close()
Gateway Device Client Quick Start¶
The following steps must be performed by a gateway device client application to allow devices to be monitored and controlled.
Initialize a gateway device client
GatewayDevice
, ensure that theconfigurationFilePath
is not pointing to a read only file as this might be modified during activationfrom iotcs.client.device.GatewayDevice import GatewayDevice ... gw = GatewayDevice(configurationFilePath, passphrase)
Activate the gateway device
if not gw.isActivated(): gw.activate()
Obtain the device model
DeviceModel
wheredeviceModelUrn
is the urn identifying the device model, for exampleurn:com:oracle:iot:device:humidity_sensor
.# the type returned by "getDeviceModel" from iotcs.client.DeviceModel import DeviceModel ... deviceModel = gw.getDeviceModel(deviceModelUrn):
Register indirectly-connected devices
# create meta-data with the indirectly-connected device's # manufacturer, model, and serial number metaData = dict() metaData[GatewayDevice.MANUFACTURER] =, "A Manufacturer" metaData[GatewayDevice.MODEL_NUMBER] = "MN-xxxx-xxxx" metaData[GatewayDevice.SERIAL_NUMBER] = "SN-yyyyyyyy" # add any vendor-specific meta-data to the metaData dictionary # register it deviceId = gw.registerDevice(hardwareId, metaData, deviceModelUrn)
Create virtual devices
VirtualDevice
implementing the device model of the indirectly connected devices.# the type returned by "createVirtualDevice" from iotcs.client.device.VirtualDevice import VirtualDevice ... virtualdevice = gw.createVirtualDevice(deviceId, deviceModel)
Listen for control operations using callbacks
ChangeCallback
,Callable
, from an enterprise client. Also implement anErrorCallback
# the VirtualDevice type from iotcs.client.VirtualDevice import VirtualDevice ... # Implement a ChangeCallback handler class OnChangeCallback(VirtualDevice.ChangeCallback): __slots__ = ( 'realdevice' ) __init__(self, realdevice): super(OnChangeCallback, self).__init__() # # provide any custom initialization or context to # reference when the "onChange" method is called # self.realdevice = realdevice def onChange(self, event): # Get the virtual device if needed virtualdevice = event.getVirtualDevice() namedvalue = event.getNamedValue() while namedValue is not None: attribute = namedvalue.getName() value = namedvalue.getValue() # # update the device with the new value # # handle multiple attribute updates self.realdevice[attribute] = value namedvalue = namedValue.next() # set the callback for any changes from the server to this virtualobject virtualdevice.setOnChange(OnChangeCallback()) # Implement a Callable handler for a "reset" action class Reset(VirtualDevice.Callable): __slots__ = ( 'realdevice' ) __init__(self, realdevice): super(Rest, self).__init__() # # provide any custom initialization or context to # reference when the "call" method is called # self.realdevice = realdevice def call(self): # # perform the reset action # self.realdevice.reset() # Set a handler for a callable action. For example, the device model # might have a 'reset' action. In this example, the action does not # require any input data. virtualdevice.setCallable("reset", Reset(theactualdevice)) # Implement a Callable handler for "calibrate" action class Calibrate(VirtualDevice.Callable): __slots__ = ( 'realdevice' ) __init__(self, realdevice): super(Calibrate, self).__init__() # # provide any custom initialization or context to # reference when the "call" method is called # self.realdevice = realdevice def call(self, zerooffset): # # calibrate the device to 'zerooffset' # self.realdevice.calibrate(zerooffset) # Set a handler for a callable action. For example, the device model # might have a 'calibrate' action. In this example, the action # requires numeric input data. virtualdevice.setCallable("calibrate", Calibrate(theactualdevice)) # Implement an ErrorCallback handler for class OnErrorCallback(VirtualDevice.ErrorCallback): __slots__ = ( 'realdevice' ) __init__(self, realdevice): super(OnErrorCallback, self).__init__() # # provide any custom initialization or context to # reference when the "call" method is called # self.realdevice = realdevice def onError(self, errorevent): # log the error logging.getLogger("onError").warn(errorevent.getMessage()) # Get the virtual device if needed virtualdevice = event.getVirtualDevice() namedvalue = event.getNamedValue() while namedValue is not None: attribute = namedvalue.getName() value = namedvalue.getValue() # # do anything to the real device if necessary # # handle multiple attribute updates namedvalue = namedValue.next() self.realdevice.reboot() # set a callback to receive errors from sending data to the server virtualdevice.setOnError(OnErrorCallback())
Update the virtual device when the data on the physical device changes
# set a value for a particular attribute in this virtual device virtualDevice.set("attribute", newValue); # or set multiple attributes in a batch operation virtualDevice.update() .set("attribute1", value1) .set("attribute2", value2) .finish();
Dispose of the virtual device
virtualdevice.close()
Dispose of the gateway device client
gw.close()