Mistake on this page? Email us

Handling Resources from a web application

Device Management Connect provides a simple REST API so web applications can interact with device Resources. Device Management Connect executes the Resource handling commands as proxy requests, meaning it responds immediately to the REST API request with an async-id and handles the device communication asynchronously.

The available operations are:

Tip: The Create and Delete operations were covered in the section about creating resources.

To see how your web application can receive notifications on Resource value changes, read Subscribing to Resource changes from a web application.

The Read operation

Device Management Connect uses the Read operation to fetch values from a device's Resources, Resource Instances and Object Instances.

The values are in the TLV format, when the operation is on:

  • The Object or Object Instance level.
  • The Resource level and the Resource has one or more Resource Instances.

The diagram illustrates a full read operation:

  1. The web application requests a device's resource value using an HTTP request with the device ID and resource path:

    GET /v2/endpoints/{device-id}/{resourcePath}

  2. Device Management Connect responds with the async-id.

  3. Device Management Connect sends a request to the device.

  4. The device responds with the resource value.

  5. Device Management Connect sends a notification containing an AsyncIDResponse to the web application via the event notification channel.

{"async-responses":{ "id" : "1131895768#f4b93d6e-4652-4874-82e4-41a3ced0cd56", "status" : 200, "payload" : "MQ==", "ct" : "text/plain", "max-age" : 300 }
  • Base64 encoded value of the payload -> MQ==
  • Base64 decoded value of the payload -> 1

Device management interface

The Write operation

You can use the Write operation to set the value of a Resource, an array of Resource Instances or multiple Resources from an Object Instance.

curl -X PUT \
  https://api.us-east-1.mbedcloud.com/v2/endpoints/{device-id}/{resourcePath} \
  -H 'authorization: Bearer {api-key}' -d '{payload}'

Whenever the server sends a valid PUT operation to a Resource(s), the device application receives a callback:

void value_updated(M2MBase* base, M2MBase::BaseType type)

M2MBase is the Object whose value has been updated, and M2MBase::BaseType is the Object type.

To handle the Write operation in your device application:

void value_updated(M2MBase* base, M2MBase::BaseType type) {
        M2MResource* resource = NULL;
        M2MResourceInstance* res_instance = NULL;
        M2MObjectInstance* obj_instance = NULL;
        M2MObject* obj = NULL;
        String object_name = "";
        String resource_name = "";
        uint16_t object_instance_id = 0;
        uint16_t resource_instance_id = 0;
        if(base) {
            switch(base->base_type()) {
                case M2MBase::Object:
                    obj = (M2MObject*)base;
                    object_name = obj->name();
                break;
                case M2MBase::ObjectInstance:
                    obj_instance = (M2MObjectInstance*)base;
                    object_name = obj_instance->name();
                    object_instance_id = obj_instance->instance_id();
                break;
                case M2MBase::Resource:
                    resource = (M2MResource*)base;
                    object_name = resource->object_name();
                    object_instance_id = resource->object_instance_id();
                    resource_name = resource->name();
                    printf("Value updated, object name %s, object instance id %d, resource name %s\r\n",
                           resource->object_name().c_str(), resource->object_instance_id(), resource->name().c_str());
                break;
                case M2MBase::ResourceInstance:
                    res_instance = (M2MResourceInstance*)base;
                    object_name = res_instance->object_name();
                    object_instance_id = res_instance->object_instance_id();
                    resource_name = res_instance->name();
                    resource_instance_id = res_instance->instance_id();
                break;
            default:
                break;
            }
        }
    }

By default, the value_updated() function handles all callbacks, but the application can define a callback function for an individual Resource if you need it:

static void value_updated_global(const char* name) {
    if(name) {
        ...
    }
}

void M2MLWClient::value_updated_function(const char* name) {
    if (name) {
        ...
    }
}

M2MResource* res = inst->create_dynamic_resource("5700", "ResourceTest", true);
char buffer[20];
int size = sprintf(buffer, "%d", _value);
res->set_operation(M2MBase::GET_PUT_POST_DELETE_ALLOWED);
res->set_value((const uint8_t*)buffer, (const uint32_t)size);
res->set_value_updated_function(value_updated_callback(this, &MbedClient::value_updated_function));
/* Overloaded function can be used If callback function is not in class scope.
res2->set_value_updated_function(value_updated_callback2(&value_updated_global));
*/

The Create operation

You can use the Create operation to create new Object Instance to the device. The Create operation MUST target an Object.

This example TLV data creates a new resource called "5700" with value "testing" under Object Instance ID "1":

curl -X POST \
  https://api.us-east-1.mbedcloud.com/v2/endpoints/{device-id}/{objectPath} \
  -H 'authorization: Bearer {api-key}' -d '{08010ae7164474657374696e67}'

For more about the TLV format, see the LwM2M spec, chapter 6.4.3.

Whenever the server sends a valid POST operation to a non existing Object Instance, the Object instance is created and the device application receives a callback:

void value_updated(M2MBase* base, M2MBase::BaseType type)

The Execute operation

Device Management Connect uses the Execute operation to perform an action on an individual Resource (there are no batch operations).

Tip: Device Management Client returns an error when it receives the Execute operation for Object Instances or Resource Instances.

To execute a function in your application:

  1. Pass a payload through a POST request from Device Management Connect. Make sure:
    • The payload is in plain text format.
    • The content-type is set as plain/text.
  2. When your Resource receives the POST request, Device Management Client parses the payload from the request and wraps it in the M2MResource::M2MExecuteParameter class. The class also contains information on which Object and Object Instance the Resource belongs to.
  3. The class object passes through the execute callback function.
  4. You can now typecast the void* argument into the corresponding M2MResource::M2MExecuteParameter and access the passed payload and its length through the given API.

Example

Here is an example:

#include "mbed-client/m2mobject.h"
#include "mbed-client/m2mobjectinstance.h"
#include "mbed-client/m2mresource.h"
    static void execute_function_2(void* argument) {
        if(argument) {
            M2MResource::M2MExecuteParameter* param = (M2MResource::M2MExecuteParameter*)argument;
            int payload_length = param->get_argument_value_length();
            uint8_t* payload = param->get_argument_value();
            String object_name = param->get_argument_object_name();
            uint16_t object_instance_id = param->get_argument_object_instance_id();
            String resource_name = param->get_argument_resource_name();
    }

    void M2MLWClient::execute_function(void* argument) {
        if(argument) {
            M2MResource::M2MExecuteParameter* param = (M2MResource::M2MExecuteParameter*)argument;
            int payload_length = param->get_argument_value_length();
            uint8_t* payload = param->get_argument_value();
            String object_name = param->get_argument_object_name();
            uint16_t object_instance_id = param->get_argument_object_instance_id();
            String resource_name = param->get_argument_resource_name();
    }

_object = M2MInterfaceFactory::create_object("3303");
if(_object) {
    M2MObjectInstance* inst = _object->create_object_instance();
    if(inst) {
	M2MResource* res = inst->create_dynamic_resource("5700", "ResourceTest", true);
        char buffer[20];
        int size = sprintf(buffer, "%d", _value);
        res->set_operation(M2MBase::GET_PUT_POST_ALLOWED);
        res->set_value((const uint8_t*)buffer,
                       (const uint32_t)size);
        res->set_execute_function(execute_callback(this, &M2MLWClient::execute_function));
        /* Overloaded function can be used If callback function is not in class scope.
        res->set_execute_function(execute_callback_2(&execute_function_2));
        */

Immediate and delayed responses

The POST method allows the client to respond immediately with the updated payload value as a piggyback response. If you want to send the payload response to the server later (because the Execute operation may take the device a long time to complete), you can handle this through the API:

  1. Set the resource API void set_delayed_response(bool) to true (its default is false).
  2. The POST request response to the server will then be an empty acknowledgment.
  3. When your Resource is ready with the response, call send_delayed_post_response() on that Resource.
  4. The client sends the latest Resource value to the server as part of a separate response to the POST request.