AirVantage Data API

API Reference
How To Manage Data

This API provides a data service to allow Apps to manage App-specific data on the AirVantage server.

IPC Interfaces Binding

All the functions of this API are provided by the avcService platform service.

Code sample for binding to avcService:

bindings:
{
   clientExe.clientComponent.le_avdata -> avcService.le_avdata
}

AirVantage Data Overview

Data is setup as Assets -- a collection of fields that can be managed by the AirVantage server.

An asset field is a single data point taken from a sensor that can be managed by the AirVantage server.

A field can be:

  • variable allowing the AirVantage server to read the value, and can be read/writtten to by an App.
  • setting allowing the AirVantage server to read/write the value, and can be read/written to by an App.
  • command allowing the AirVantage server to invoke a function in the App.

Fields are referred to by paths and need to follow these rules:

  • A parent path can't contain a field, parent path or child path that has the same name.
  • Paths must be separated by a slash ("/") or a dot (".").
  • When using a ("/") the path must start with a ("/") (e.g., /a/b/c)
  • When using a (".") the path must start with the first field, (e.g., a.b.c)
Note
There is no leading "." when using "." delimiter.

Variable and setting fields also have types. The available field types are:

  • string
  • integer
  • float
  • boolean

Variable and setting fields have no default values. When they are first created with the le_avdata_CreateResource() , all values are "null". They can also be set to "null" values with the le_avdata_SetNull() .

Fields do not have a fixed data type, so any of the SetInt/Float/Bool/String can be called for a certain field to change its value and its type. However, A GetInt/Float/Bool/String API must be called on a field with the matching type. In other words, a Get API does not perform type-casting.

Note
If a user enters a value 0 for float data type, an error will be returned (LE_NOT_FOUND), as the system infers 0 as an integer value and the data type doesn't match. 0.0 needs to be set for the float data type to be zero.

Field Values and Activity

Set functions are available to set field values (including "null"). Get functions are available to get field values.

An App can register a handler so that it can be called when an activity occurs on a field. This is optional for variable and setting fields, but is required for command fields. Registered handlers are called only when activities from AV server occurs. Client activities do not trigger handlers.

A handler registered with a command field is invoked with an optional argument list sent from the AirVantage server. The APIs GetInt/Float/Bool/StringArg and le_avdata_GetStringArgLength() are available to extract the arguments in the handler definition. AV server does not send argument lists for handlers registered with variable and setting fields.

A handler registered with a command field must call the le_avdata_ReplyExecResult() at the end of its definition, in order to reply the command execution result to the AV server.

Sometimes instead of waiting for activity to occur on a field, users may want to have their application notify the server of their asset data details. Asset data can also be pushed from the device to the server by using le_avdata_Push().

This code sample shows how to push asset data to the server (assuming session is opened)

static void PushCallbackHandler
(
void* contextPtr
)
{
if (status == LE_AVDATA_PUSH_SUCCESS)
{
// data pushed successfully
}
}
 
{
le_result_t result;
result = le_avdata_CreateResource("/livingRoom/sensor1", LE_AVDATA_ACCESS_VARIABLE);
if (result != LE_OK)
{
LE_FATAL("Error in creating livingRoom resource.");
}
 
result = le_avdata_SetInt("/livingRoom/sensor1", 5) == LE_OK);
if (result != LE_OK)
{
LE_FATAL("Failed to set value for livingRoom resource.");
}
 
le_avdata_Push("/livingRoom/sensor1", PushCallbackHandler, NULL);
}

If users simply want to push a data dump to the server without creating resources, le_avdata_PushStream() is available.

Note
The push stream API has a limit of 20K.
{
int fd = open("data.txt", O_RDONLY);
if (fd == -1)
{
LE_FATAL("Failed to open file.");
}
 
// The data dump sent to the server will be display under <Path>
le_avdata_PushStream("<Path>", fd, PushCallbackHandler, NULL);
}

Namespace

By default all asset data paths are created and managed under the application namespace. Calling le_avdata_GetXXX / le_avdata_SetXXX/ le_avdata_AddResourceEventHandler() / le_avdata_Push() with the path "/a/b/c" will search for the "/a/b/c" data under the apps namespace. In order to query any paths created under an application namespace, user must append the app name in front of the request on the server side. If creating asset data under application namespace is not desired, users must call le_avdata_SetNamespace() and set the value to global. An application that changes its namespace to global will be creating asset data in the global space. All asset data API will use the last namespace set until the function is called again and the namespace is set to something new.

Note
Asset data settings are persistent after an application restart or device reboot, regardless of the namespace used to create it. The asset data settings are restored lazily when the app or server reads the setting.

Example:

#define RESOURCE_A "/test/resourceA"
 
{
int intVal;
LE_ASSERT(le_avdata_SetInt(RESOURCE_A, 1) == LE_OK);
LE_ASSERT(le_avdata_GetInt(RESOURCE_A, &intVal) == LE_OK);
LE_ASSERT(intVal == 1); // value obtained under the application namespace
 
// Switch to global namespace
LE_ASSERT(le_avdata_SetNamespace(LE_AVDATA_NAMESPACE_GLOBAL) == LE_OK);
 
LE_ASSERT(le_avdata_SetInt(RESOURCE_A, 2) == LE_OK);
LE_ASSERT(le_avdata_GetInt(RESOURCE_A, &intVal) == LE_OK);
LE_ASSERT(intVal == 2); // value obtained under the global namespace
}

An application starts by creating a path "/test/resourceA" under the default application namespace and sets it to 1. Then it sets the namespace to global and creates another path "/test/resourceA" with a value of 2. A read request from the server on "<appName>/test/resourceA" will return 1; whereas a read request on "/test/resourceA" will return 2. A read request from the server on a parent node will result in reading multiple resources together. For example, a read request on "<appName>/test" will result in a response containing relative paths and values of resourceA and resourceB.

Time Series

This feature enables user Apps to collect and keep in memory data when the device is off-line and send the data to the AirVantage Server when the device is on-line.

Time series records can be initialized using le_avdata_CreateRecord(). Data can be accumulated using the following data types along with a specified time stamp (milliseconds elapsed since epoch).

User apps can then open an avms session, and push the collected history data using le_avdata_PushRecord(). The callback used when calling le_avdata_PushRecord() will indicate whether the push has been successful or not.

This code sample shows how to collect data and send to the server (assuming session is opened)

static void PushCallbackHandler
(
void* contextPtr
)
{
if (status == LE_AVDATA_PUSH_SUCCESS)
{
// data pushed successfully
}
}
 
static void SendData()
{
struct timeval tv;
uint64_t utcMilliSec;
le_result_t result;
 
 
gettimeofday(&tv, NULL);
utcMilliSec = (uint64_t)(tv.tv_sec) * 1000 + (uint64_t)(tv.tv_usec) / 1000; // get current time
result = le_avdata_RecordFloat(recRef, "speed", 0.08, utcMilliSec);
 
if (result == LE_OK)
{
le_avdata_PushRecord(recRef, PushCallbackHandler, NULL);
}
 
}

User App Session Management

An App can request to open a session and register a handler to get notified of a session events. le_avdata_RequestSession() and le_avdata_ReleaseSession() can be used to open a session and close a session respectively. If the session was initiated by an user app, the session will be closed when all apps release their session reference. le_avdata_AddSessionStateHandler() and le_avdata_RemoveSessionStateHandler() can be used to add and remove notification handlers.

Fatal Behavior

An invalid asset name or field name is treated as a fatal error (i.e. non-recoverable) and will result in the client App being terminated.

AV Data Buffer Limitation

The number of resources that can be read/written together is limited by the buffer size defined by avc client. There are three buffers that determines how many resources can be read/written/pushed together.

  • COAP_BLOCK1_SIZE - Determines the number of resource that can be written together
  • AVDATA_READ_BUFFER_BYTES - Determines the number of resource that can be read together
  • AVDATA_PUSH_BUFFER_BYTES - Determines the number of resource that can be pushed together

All the buffers are set to 4096 bytes by default. Users can increase the buffer size if an application needs to operate on a parent path with a large number of resources under it.

Note
Having more than 5000 resources under a parent path is not advisable for several reasons: If the network is lost or device resets while the payload is being transferred, the read/write operation will fail and has to be re-triggered. Large number of settings will also slow down avc startup.