API Usage
PUBLISHED
The following figure illustrates the SmartThings™ Things API life-cycle.
Figure: SmartThings™ Things API life-cycle
Initializing Stack and Callbacks
Once the device configuration JSON file is ready, you can specify the read-only and read-write paths in the st_things_set_configuration_prefix_path()
function (optional), and specify the file in the st_things_initialize()
function:
bool easysetup_complete = false; st_things_set_configuration_prefix_path("/ropath/XXX/res", "/rwpath/XXX/data"); /* Optional */ st_things_initialize("sample_device.json", &easysetup_complete); /* User input can be handled graphically or using CLI */ /* You need to decide that */ if (!easysetup_complete) { int cmd = 0; printf("[%s]Start Easysetup ? (1:yes, other:no): ", TAG); scanf("%d", &cmd); if (1 != cmd) { st_things_deinitialize(); return 0; } } /* Register Callbacks */ st_things_register_request_cb(handle_get_request, handle_set_request); st_things_register_reset_cb(handle_reset_request, handle_reset_result); st_things_register_user_confirm_cb(handle_ownership_transfer_request); st_things_register_things_status_change_cb(handle_things_status_change); st_things_start(); printf("ST Things Stack started\n"); handle_main_loop(); st_things_stop(); printf("ST Things Stack Stopped\n"); st_things_deinitialize(); printf("ST Things Stack deinitialized\n");
You must define the highlighted code in the above example. The st_XXX()
functions come from the ST Things SDK API. For more information, see the API Documentation.
Getting and Setting Request Handling Callbacks
Assume that the following resources and resource types are defined in the sample_device.json
file:
Example: Resources and resource types
"resources": { "single": [ { "uri": "/switch", "types": [ "oic.r.switch.binary" ], "interfaces": [ "oic.if.a", "oic.if.baseline" ], "policy": 3 }, { "uri": "/audio", "types": [ "oic.r.audio" ], "interfaces": [ "oic.if.a", "oic.if.baseline" ], "policy": 3 } ] } |
"resourceTypes": [ { "type": "oic.r.switch.binary", "properties": [ { "key": "value", "type": 0, "mandatory": true, "rw": 3 } ] }, { "type": "oic.r.audio", "properties": [ { "key": "volume", "type": 1, "mandatory": true, "rw": 3 }, { "key": "mute", "type": 0, "mandatory": true, "rw": 3 } ] } ] |
The 2 defined resources are:
- Switch (URI =
"/switch"
) - Audio (URI =
"/audio"
)
The following example illustrates the get and set request handlers:
static const char* RES_SWITCH = "/switch"; static const char* RES_AUDIO = "/audio"; bool handle_get_request(st_things_get_request_message_s* req_msg, st_things_representation_s* resp_rep) { printf("[%s]Received a GET request on %s\n", TAG, req_msg->resource_uri); bool ret = false; if (0 == strcmp(req_msg->resource_uri, RES_SWITCH)) { ret = handle_get_request_on_switch(req_msg, resp_rep); } else if (0 == strcmp(req_msg->resource_uri, RES_AUDIO)) { ret = handle_get_request_on_audio(req_msg, resp_rep); } else { printf("[%s]Not supported uri.\n", TAG); } return ret; } bool handle_set_request(st_things_set_request_message_s* req_msg, st_things_representation_s* resp_rep) { printf("[%s]Received a SET request on %s\n", TAG, req_msg->resource_uri); bool ret = false; if (0 == strcmp(req_msg->resource_uri, RES_SWITCH)) { ret = handle_set_request_on_switch(req_msg, resp_rep); } else if (0 == strcmp(req_msg->resource_uri, RES_AUDIO)) { ret = handle_set_request_on_audio(req_msg, resp_rep); } else { printf("[%s]Not supported uri.\n", TAG); } return ret; }
The key difference is the req_msg->resource_uri
value passed in the callbacks to distinguish the 2 resources. Since the resource URI is unique in the device definition, each resource can be handled separately.
The following examples illustrate the get and set request handling callbacks for a single and multiple properties:
- For a single property, you must extract the desired property from the request message and update the device property database locally. Once you have updated the device property, you must update the response representation about the updated property which is sent to the client:
#define TAG "DEVELOPER_DEVICE" static const char* PROPERTY_VALUE = "value"; bool g_switch_value = false; bool handle_get_request_on_switch(st_things_get_request_message_s* req_msg, st_things_representation_s* resp_rep) { printf("[%s]IN-handle_get_request_on_switch() called..\n", TAG); printf("[%s]current switch value: %d\n", TAG, g_switch_value); resp_rep->set_bool_value(resp_rep, PROPERTY_VALUE, g_switch_value); printf("[%s]OUT-handle_get_request_on_switch() called..\n", TAG); return true; } bool handle_set_request_on_switch(st_things_set_request_message_s* req_msg, st_things_representation_s* resp_rep) { printf("[%s]IN-handle_set_request_on_switch() called..\n", TAG); printf("[%s]current switch value: %d\n", TAG, g_switch_value); bool desired_value = false; req_msg->rep->get_bool_value(req_msg->rep, PROPERTY_VALUE, &desired_value); printf("[%s]desired switch value: %d\n", TAG, desired_value); g_switch_value = desired_value; printf("[%s]changed switch value: %d\n", TAG, g_switch_value); resp_rep->set_bool_value(resp_rep, PROPERTY_VALUE, g_switch_value); printf("[%s]OUT-handle_set_request_on_switch() called..\n", TAG); return true; }
- For multiple properties, the process is the same, except that you need to handle multiple properties at the same time:
#define TAG "DEVELOPER_DEVICE" static const char* PROPERTY_VOLUME = "volume"; static const char* PROPERTY_MUTE = "mute"; int64_t g_audio_volume = 0; bool g_audio_mute = false; bool handle_get_request_on_audio(st_things_get_request_message_s* req_msg, st_things_representation_s* resp_rep) { printf("[%s]IN-handle_get_request_on_audio() called..\n", TAG); printf("[%s]current audio volume: %"PRId64".\n", TAG, g_audio_volume); printf("[%s]current audio mute: %d.\n", TAG, g_audio_mute); resp_rep->set_int_value(resp_rep, PROPERTY_VOLUME, g_audio_volume); resp_rep->set_bool_value(resp_rep, PROPERTY_MUTE, g_audio_mute); printf("[%s]OUT-handle_get_request_on_audio() called..\n", TAG); return true; } bool handle_set_request_on_audio(st_things_set_request_message_s* req_msg, st_things_representation_s* resp_rep) { printf("[%s]IN-handle_set_request_on_audio() called..\n", TAG); printf("[%s]current audio volume: %"PRId64".\n", TAG, g_audio_volume); printf("[%s]current audio mute: %d\n", TAG, g_audio_mute); int64_t desired_volume = 0; bool desired_mute = false; req_msg->rep->get_int_value(req_msg->rep, PROPERTY_VOLUME, &desired_volume); req_msg->rep->get_bool_value(req_msg->rep, PROPERTY_MUTE, &desired_mute); printf("[%s]desired audio volume: %"PRId64".\n", TAG, desired_volume); printf("[%s]desired audio mute: %d.\n", TAG, desired_mute); g_audio_volume = desired_volume; g_audio_mute = desired_mute; printf("[%s]changed audio volume: %"PRId64".\n", TAG, g_audio_volume); printf("[%s]changed audio mute: %d.\n", TAG, g_audio_mute); resp_rep->set_int_value(resp_rep, PROPERTY_VOLUME, g_audio_volume); resp_rep->set_bool_value(resp_rep, PROPERTY_MUTE, g_audio_mute); printf("[%s]OUT-handle_set_request_on_audio() called..\n", TAG); return true; }
Notifying Observers
The following example illustrates how you can notify observers:
#define TAG "DEVELOPER_DEVICE" static const char* RES_SWITCH = "/switch"; static const char* RES_AUDIO = "/audio"; static const char* PROPERTY_VALUE = "value"; bool g_switch_value = false; bool notify_observers(const char *resource_uri) { printf("[%s] Notify all observers for resource = %s\n", TAG, resource_uri); bool ret = false; if (0 == strcmp(resource_uri, RES_SWITCH)) { ret = st_things_notify_observers(resource_uri); } else if (0 == strcmp(resource_uri, RES_AUDIO)) { ret = st_things_notify_observers(resource_uri); } else { printf("[%s]Not supported uri.\n", TAG); } return ret; } bool handle_set_request_on_switch(st_things_set_request_message_s* req_msg, st_things_representation_s* resp_rep) { printf("[%s]IN-handle_set_request_on_switch() called.\n", TAG); printf("[%s]current switch value: %d\n", TAG, g_switch_value); bool is_value_changed = false; bool desired_value = false; req_msg->rep->get_bool_value(req_msg->rep, PROPERTY_VALUE, &desired_value); printf("[%s]desired switch value: %d\n", TAG, desired_value); if (g_switch_value = desired_value) { g_switch_value = desired_value; is_value_changed = true; } resp_rep->set_bool_value(resp_rep, PROPERTY_VALUE, g_switch_value); if (is_value_changed) { notify_observers(req_msg->resource_uri); } printf("[%s]OUT-handle_set_request_on_switch() called..\n", TAG); return true; }
IoTivity Information
The following table lists the resource types supported by IoTivity.
Table: IoTivity resource types
Resource type name | Resource type value |
---|---|
Device | oic.wk.d |
Platform | oic.wk.p |
Discovery | oic.wk.res |
Presence | oic.wk.ad |
Collection | oic.wk.col |
The following table shows the IoTivity interfaces that specify how the device returns its response. These interfaces can be used by the IoTivity client (such as Samsung Connect) to retrieve information from the server (device).
Table: IoTivity interfaces for responses
Name | Interface | Description |
---|---|---|
Baseline | oic.if.baseline |
Includes all information about the resource, including metadata and collection information. This is the default interface type. |
Linked List | oic.if.ll |
Includes only the collection information about the resource. This is the default interface type for /oic/res . |
Batch | oic.if.b |
Allows for the aggregation of interaction with all resources. Each resource is interacted with separately, but their responses are aggregated. |
The following table lists other interface types that are related to permissions. These interfaces are relevant for retrieve and update requests.
Table: IoTivity interfaces for permissions
Name | Interface | Description |
---|---|---|
Read | oic.if.r |
Allows values to be read. |
Read Write | oic.if.rw |
Allows values to be read and written. |
Actuator | oic.if.a |
Allows creating, updating, and retrieving actuator values. |
Sensor | oic.if.s |
Allows sensor values to be read. |
Was this document helpful?
We value your feedback. Please let us know what you think.