Trusted Assets
Trusted assets are defined as material that contribute to the chain of trust between the client and the server. The client library relies on an implementation of the TrustedAssetsManager to securely manage these assets on the client. The client-library has a default implementation of the TrustedAssetsManager which uses a framework native trust-store to secure the trust assets. To create the trust-store for the default TrustedAssetsManager, the user must run the TrustedAssetsProvisioner tool by using the script provided in the tools depending if the provision is made for the enterprise or device client library. Usage is available by running the tool without arguments.Device Models
A device model is a predefined specification of the attributes, 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. 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
(iotcs.enterprise.EnterpriseClient#getDeviceModel
or
iotcs.device.DirectlyConnectedDevice#getDeviceModel
). This will generate for a
specified urn the device model associated with it and registered
in the cloud as JSON objects that contain all the attributes, actions
ant other specific information for a device model. With the generated
model a virtual device can be created that encapsulates all the
device functionality based on a specific model. If a device has more
than one model associated, for each model a different virtual device
can be crated and monitored/controlled.
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 isoffered
to a iotcs.device.VirtualDevice
.
Enterprise Client
Both enterprise and device clients share common API for getting and setting values through a user-interface (in the case of an enterprise-client application) and for getting and setting values on a physical device (in the case of a device-client application).
An enterprise-client application will create an iotcs.enterprise.EnterpriseClient
based on an application already created on the server using the static method
iotcs.enterprise.EnterpriseClient.newClient
. A list of applications that the user has access to can be
retrieved by using the static method iotcs.enterprise.EnterpriseClient.getApplications
.
From there, the application can list all the device models
that are registered with it by using iotcs.enterprise.EnterpriseClient#getDeviceModels
.
After selecting models the list of active devices that have the selected
models can be retrieved by using iotcs.enterprise.EnterpriseClient#getActiveDevices
.
After selecting combination of models/devices, using the device id's and retrieved
models the application can create instances of iotcs.enterprise.VirtualDevice
which provides access to monitor and control the devices.
Device Client
A device-client application will create aiotcs.device.DirectlyConnectedDevice
or
a iotcs.device.GatewayDevice
(for indirectly connected devices registration)
based on a device already registered on the server that has a logical ID already assigned
and saved in a {endpointId}.json generated based on that ID and shared secret
associated with the device registered by the TrustedAssetsProvisioner. If the device should
be checked if is activated and if is not then the activation should be done.
In the course of the activation trusted material used for future authentication with
the server will be generated by the TrustedAssetsManager and saved in the
{endpointId}.json. In the activation method the model URN's (and capabilities) that the client
is implementing (if any) must be given as parameters.
After activation (done only if needed) the client should retrieve the device models for the
URN's that it is implementing or that other indirectly connected device that is registering
in the future are implementing by using the iotcs.device.DirectlyConnectedDevice#getDeviceModel
or iotcs.device.GatewayDevice#getDeviceModel
methods.
If the client is a iotcs.device.GatewayDevice
, it can use the
iotcs.device.GatewayDevice#registerDevice
method to register other indirectly
connected devices that it is using. The server will assign logical endpoint id's to
these devices and return them to the client.
Be aware that all endpoint id's assigned by the server to indirectly connected
devices must be persisted and managed by the device application to use them for creating
virtual devices. There is no method for retrieving them from the server side and at
an eventual device application restart the id's must be reused.
After selecting combination of logical endpoint id's (including the client own id) and
device models, the client can create instances of iotcs.device.VirtualDevice
by
using the constructor or the iotcs.device.DirectlyConnectedDevice#createVirtualDevice
and iotcs.device.GatewayDevice#createVirtualDevice
methods which provides
access to messaging to/from the cloud for the specific logical devices.
Examples
Enterprise Client Quick Start
//The following steps must be taken to run an enterprise-client application.
var appName;
var ec;
var model;
var deviceId;
var device;
// 1. Select an application
iotcs.enterprise.EnterpriseClient
.getApplications()
.page('first')
.then(response=>{
response.items.forEach(item => {
//select and application and set appName (the application name)
});
initializeEnterpriseClient();
}, error => {
//handle error in enumeration
});
// 2. Initialize enterprise client
function initializeEnterpriseClient(){
iotcs.enterprise.EnterpriseClient.newClient(appName, (client, error) => {
if (!client || error) {
//handle client creation error
}
ec = client;
selectDeviceModel();
}
}
// 3. Select a device model available in the app
function selectDeviceModel(){
ec.getDeviceModels()
.page('first')
.then(response => {
response.items.forEach(item => {
//select a device model and set model
});
selectDevice();
}, error => {
//handle error in enumeration
});
}
// 4. Select an active device implementing the device model
function selectDevice(){
ec.getActiveDevices(model)
.page('first')
.then(response => {
response.items.forEach(item => {
//select a device and set the deviceId
});
createVirtualDevice();
}, error => {
//handle error in enumeration
});
}
// 5. Create a virtual device for this model
function createVirtualDevice(){
device = ec.createVirtualDevice(deviceId, model);
monitorVirtualDevice();
updateVirtualDeviceAttribute();
executeVirtualDeviceAction();
}
// 6. Monitor the device through the virtual device
function monitorVirtualDevice(){
device.onChange = onChangeTuple => {
//print the new value and attribute
console.log('Attribute '+onChangeTuple.attribute.name+' changed to '+onChangeTuple.newValue);
//process change
};
device.onAlerts = alerts => {
for (var key in alerts) {
alerts[key].forEach(alert => {
//print alert
console.log('Received time '+alert.eventTime+' with data '+JSON.stringify(alert.fields));
//process alert
});
}
};
}
// 7. Update the value of an attribute
function updateVirtualDeviceAttribute(){
device.onError = onErrorTuple => {
//handle error case on update
};
device.attributeName.value = someValue;
}
// 8. Execute action on virtual device
function executeVirtualDeviceAction(){
device.someAction.onAction = response => {
//handle execute action response from server
};
device.call('someAction');
}
// 9. Dispose of the device
device.close();
// 10. Dispose of the enterprise client
ec.close();
Device Client Quick Start
//The following steps must be taken to run a device-client application. This
//sample is for a gateway device that does not implement any specific model
//that registers one indirectly connected device.
//The model must be already in the cloud registered.
var trustedAssetsFile = '0-SOMEID.json';
var trustedAssetsPassword = 'changeit';
var gateway;
var model;
var indirectDeviceId;
var indirectDevice;
var indirectDeviceSerialNumber = 'someUniqueID' ;
var indirectDeviceMetadata = {};
// 1. Create the device client (gateway)
gateway = new iotcs.device.GatewayDevice(trustedAssetsFile, trustedAssetsPassword);
// 2. Activate the device if needed
if (!gateway.isActivated()) {
gateway.activate([], (device, error) => {
if (!device || error) {
//handle activation error
}
selectDeviceModel();
});
} else {
selectDeviceModel();
}
// 3. Select the device model
function selectDeviceModel(){
gateway.getDeviceModel('urn:myModel', (response, error) => {
if (!response || error) {
//handle get device model error
}
model = response;
enrollDevice();
});
}
// 4. Register an indirectly connected device
function enrollDevice(){
gateway.registerDevice(indirectDeviceSerialNumber, indirectDeviceMetadata, ['urn:myModel'],
(response, error) => {
if (!response || error) {
//handle enroll error
}
indirectDeviceId = response;
createVirtualDevice();
});
}
// 5. Create a virtual device for the indirectly connected device
function createVirtualDevice(){
device = gateway.createVirtualDevice(deviceId, model);
monitorVirtualDevice();
updateVirtualDeviceAttribute();
sendVirtualDeviceAlert();
}
// 6. Monitor the device through the virtual device (it has two actions: power and reset)
function monitorVirtualDevice(){
device.onChange = onChangeTuple => {
//print the new value and attribute
console.log('Attribute '+onChangeTuple.attribute.name+' changed to '+onChangeTuple.newValue);
//process change
throw new Error('some message'); //if some error occurred
};
device.power.onAction = value => {
if (value) {
//shutdown the device
} else {
//start the device
}
};
device.reset.onAction = () => {
//reset the device
throw new Error('some message'); //if some error occurred
};
}
// 7. Update the value of an attribute
function updateVirtualDeviceAttribute(){
device.onError = onErrorTuple => {
//handle error case on update
};
device.attributeName.value = someValue;
}
// 8. Raise an alert to be sent to the cloud
function sendVirtualDeviceAlert(){
var alert = device.createAlert('urn:myAlert');
alert.fields.mandatoryFieldName = someValue;
alert.fields.optionalFieldName = someValue; //this is optional
alert.raise();
}
// 9. Dispose of the virtual device
device.close();
// 10. Dispose of the gateway device client
ec.close();
Storage Cloud Quick Start
// This shows how to use the Virtualization API to upload content to,
// or download content from, the Oracle Storage Cloud Service.
// To upload or download content, there must be an attribute, field,
// or action in the device model with type URI.
// When creating a DataItem for an attribute, field, or action of type URI,
// the value is set to the URI of the content in cloud storage.
//
// Uploading content
//
// An instance of iotcs.device.StorageObject is first needed to upload a file
// from a device client or from an enterprise client.
// The StorageObject is created using the createStorageObject API in iotcs.Client,
// which is the base class for iotcs.enterprise.EnterpriseClient, iotcs.device.DirectlyConnectedDevice,
// and iotcs.device.GatewayDevice. The StorageObject names the object in storage,
// and provides the mime-type of the content.
// To set the input path, the StorageObject API setInputPath(string path) is used.
// This example shows the typical use case from a DirectlyConnectedDevice.
// But the code for a GatewayDevice or EnterpriseClient is the same.
var storageObjectUpload = gateway.createStorageObject("uploadFileName", "image/jpg");
storageObjectUpload.setInputPath("upload.jpg");
virtualDevice.attributeName.value = storageObjectUpload;
// OR
virtualDevice.update({attributeName: storageObjectUpload});
// A StorageObject may also be set on an Alert field, or as an Action parameter,
// provided the type in the device model is URI
//
// Downloading content
//
// In the Virtualization API, the client is notified through an onChange tuple,
// onAlert tuple, or a call callback for an action. The value in the tuple is a StorageObject.
// To download the content, the output path is set on the StorageObject,
// and the content is synchronized by calling the StorageObject sync() API.
// This example shows the typical use case from an onChange event.
// The code for an onAlert or for an action callback is much the same.
virtualDevice.attributeName.onChange = tuple => {
var name = tuple.attribute.id;
var storageObject = tuple.newValue;
// only download if image is less than 4M
if (storageObject.getLength() < 4 * 1024 * 1024) {
storageObject.setOutputPath("download.jpg");
storageObject.sync();
}
};
//
// Checking synchronization status
//
// A StorageObject is a reference to some content in the Storage Cloud.
// The content can be in sync with the storage cloud, not in sync with the storage cloud,
// or in process of being sync'd with the storage cloud.
// The synchronization can be monitored by setting a SyncCallback with onSync.
// For the upload case, set the onSync callback on the storage object
// before setting the virtual device attribute.
// For the download case, set the onSync callback on the storage object
// from within the onChange callback.
storageObject.onSync = event => {
var sourceStorageObject = event.getSource();
if (sourceStorageObject.getSyncStatus() === iotcs.device.StorageObject.SyncStatus.IN_SYNC) {
// image was uploaded
} else if (sourceStorageObject.getSyncStatus() === iotcs.device.StorageObject.SyncStatus.FAILED) {
// image was not uploaded, take action!
}
}