:::hw
Board|Eagleye 530s Board|1 ea|based on ARTIK 530s w/flashed Tizen 4.0
:::hw
Sensor|Sensor |1 ea|SRF02 Ultrasonic Range Finder Module
:::hw
Etc.|others|| PC or Laptop w/Windows or Mac OS
:::hw
Etc.|others|| Mobile Device installed SmartThings App
:::
:::sw
OS|Tizen 4.0|with IOT platform image
:::sw
SDK|TizenStudio 2.4|& IoT-Headless Extension SDK
:::sw
SDK|SmartThings SDK|Atom IDE, Node.js, JavaSE, JCE
:::
# Prerequisite
If you need an information about the following subject, Refer to the link of each item. Those will be mentioned in this article.
## [Tizen](https://www.tizen.org/)
[Tizen Development](https://developer.tizen.org/)
[Tizen IoT application development](https://developer.tizen.org/development/iot-preview/getting-started)
[Tizen Things SDK API](https://developer.tizen.org/ko/development/iot-preview/iot-apis/things-sdk-api/device-definition)
## [SmartThings](https://smartthings.developer.samsung.com/develop/index.html)
[Creating & Registering new SmartThings Device included Tizen IoT device](https://smartthings.developer.samsung.com/develop/getting-started/cloud-connected.html)
[Install SDK for development plugin](https://smartthings.developer.samsung.com/develop/workspace/general-tools/sdk.html)
[Developing SmartThing Plugin](https://smartthings.developer.samsung.com/develop/guides/plugin/overview.html)
[SmartThings SDK](https://developer.tizen.org/dev-guide/things-sdk/index.html)
## [Eagleye Board](http://wiki.seeedstudio.com/Eagleye_530s/)
[How to flash Eagleye 530s Board](https://wiki.tizen.org/Tizen_IoT/reference_board)
## [Ultrasonic Range Sensor](http://www.robot-electronics.co.uk/htm/srf02tech.htm)
# Introduction
I will describe how to make Range Finder using ultrasonic sensor as IoT things device that can detect **distance** remotely using SmartThings App on mobile Device.
First, let's take a brief look at **Ultrasonic** before we start this project.
### About Ultrasonic ###
The term "ultrasonic" applied to sound refers to anything above the frequencies of audible sound, and nominally includes anything over 20,000 Hz.
Sounds in the range 20-100kHz are commonly used for communication and navigation.
Ultrasound is sound waves with frequencies higher than the upper audible limit of human hearing.
Ultrasound is used in many different fields. Ultrasonic devices are used to detect objects and measure distances. Ultrasound imaging or sonography is often used in medicine. In the nondestructive testing of products and structures, ultrasound is used to detect invisible flaws. Industrially, ultrasound is used for cleaning, mixing, and to accelerate chemical processes.
For more information about **Ultrasonic**, please click [here](https://en.wikipedia.org/wiki/Ultrasound).
### Devices used for this project ###
I use a Eagleye 530s Board as IoT target and SRF02 ultrasonic sensor module. These look like this:

>**About Target Controller : Eagleye 530s Board**
The Eagleye 530s is a high-performance, pre-tested, cost-effective and production-ready development kit which incorporates the Samsung ARTIK 530s--a 1GB system-on-module (SoM)-- on a custom credit card size board. For more information about Eagleye 530s, please click [here](http://wiki.seeedstudio.com/Eagleye_530s/).
>**SRF02 Ultrasonic range finder Module**
The SRF02 is a single transducer ultrasonic rangefinder. It features both I2C and a Serial interfaces and Up to 16 SRF02's may be connected together on a single bus, either I2C or Serial. New commands in the SRF02 include the ability to send an ultrasonic burst on its own without a reception cycle, and the ability to perform a reception cycle without the preceding burst. Because the SRF02 uses a single transducer for both transmission and reception, the minimum range is higher than our other dual transducer rangers.
Reference Links: http://www.robot-electronics.co.uk/htm/srf02tech.htm
Features are as the belows:
*- Range: 16cm to 6m.*
*- Power: 5v, 4mA Typ.*
*- Frequency: 40KHz.*
*- Analogue Gain: Automatic 64 step gain control*
*- Support 2 connection modes: Standard I2C Bus / Serial Bus(UART)*
*- Full Automatic Tuning: No calibration, just power up and go*
*- Units: Range reported in uS, mm or inches.*
>**About I2C Interface**
The I2C bus was designed by Philips in the early '80s to allow easy communication between components which reside on the same circuit board.
The name of I2C bus is sometimes called IIC bus.
I2C uses only two bidirectional open collector or open drain lines, Serial Data Line (SDA) and Serial Clock Line (SCL), pulled up with resistors.
All I2C master and slave devices are connected with only those two wires. Each device can be a transmitter, a receiver or both. Some devices are masters ??they generate bus clock and initiate communication on the bus, other devices are slaves and respond to the commands on the bus. In order to communicate with specific device, each slave device must have an address which is unique on the bus. I2C master devices (usually microcontrollers) do not need an address since no other (slave) device sends commands to the master.
The I2C reference design has a 7-bit address space, with a rarely-used 10-bit extension.
Common I2C bus speeds are the 100 kbit/s standard mode and the 400 kbit/s Fast mode and many applications do not require faster transmissions.
I2C is not only used on single boards but also to connect components which are linked via cable. Simplicity and flexibility are key characteristics that make this bus attractive to many applications.
Typical voltages used are +5 V or +3.3 V, although systems with other voltages are permitted.
For more information about I2C, please click [here](https://en.wikipedia.org/wiki/I%C2%B2C).
### How to connect ###
let's connect this sensor with Eagleye 530s board.
As described in the above, SRF02 module comunicate with controller through UART or I2C bus Interface.
I will use I2C Bus interface, so I need to connect to I2C ports in power off state of eagleye 530s board.
Connection diagram is as the following. The wiring is very simple.

For referance, the IO pin of eagleye board is shown in the picture.

### Implement Procedure
Here is 5 steps on how to implement IoT device app & SmartThings plugin.
>
- **Define Function to to select resource(Capability)**
- **Register Device To SmartThings Cloud**
- **Implement IoT Device Application**
- **Implement ST Plugin**
- **Test Operation**

These are all described on the below as underlined title.
*****
# Define Function to select Capability
First of all, we have to define sensor target function.
It's quite simple functions as just detecting sensor value.
I described three major functions in here as below.
**Enable/Disable Sensor Function**
**Display/Update Sensor Value**
**Return Presence Status**
As the above, just three types of functions are required for this.
In SmartThings web, this function can be defined as **capabilities** for inter-communication with IoT device respectively.
### Select Capability
Since SmartThings API provides various capability with unique properties, we have to select capabilities that match the target functions.
In SmartThings developer website, we can refer capability and OCF resource type for it.
https://smartthings.developer.samsung.com/develop/api-ref/capabilities.html
I select three capabilities matching with above functionality as the following.
**Enable/Disable Function** : [**Switch** Capability](https://smartthings.developer.samsung.com/develop/api-ref/capabilities.html#Switch)
**Display/Update Sensor Value** : [**Illuminance Measurement** Capability](https://smartthings.developer.samsung.com/develop/api-ref/capabilities.html?highlight=IlluminanceMeasurement#Illuminance-Measurement)
**Return Presence Status** : [**Presence Sensor** Capability](https://smartthings.developer.samsung.com/develop/api-ref/capabilities.html#Presence-Sensor)
Functional diagram by capabilities is as the following:

*****
# Register Device To SmartThings Cloud.
A cloud-connected device communicates directly with SmartThings Cloud, using the OCF specification over a CoAP stack. We can directly control cloud-connected devices with the SmartThings app.
SmartThings app is able to use a default plugin for IoT devices that simply use predefined capabilities. Therefore, you just register a device, you can directly use the device without coding.
Now, Go to the SmartThings Developer Workspace to register new device!
https://devworkspace.developer.samsung.com/smartthingsconsole/iotweb/site/index.html#/main

>**Important Notice**

In the web site, go to **Development** > **SmartThings Device** > **Cloud-connected** and click **+ Create**.

To register your device, you need to fill some fields (vid, capability, etc)
Each field of registeration form is described in the following image.

Then, you can create and register new device.
For more information on creating a cloud-connected device using the Developer Workspace, please click [here](https://smartthings.developer.samsung.com/develop/getting-started/cloud-connected.html).
After creating device, you can see the device in the list view and information of it's including capability to be used.


And you can check generated meta files as below:
UI meta file name will have the following format.
**<MNID>_<VID>_ui.json**
>**Important Notice**
Device Name, Capabilities, MNID(Manufacturer ID) and VID(Vendor ID) should be the same of those in your device definition file.

*****
# Implement IoT Device Application
Here is described how to proceed IoT device application implementation.
It is supposed to be completed the environment for developing IoT device app.
If not, you should check [Tizen IoT application development](https://developer.tizen.org/development/iot-preview/getting-started)
Now you run Tizen Studio and create new project.
In the Tizen Studio, select **File** > **New** > **Tizen Project**
the following link is helpful:
https://developer.tizen.org/development/iot-preview/getting-started-tizen/developing-applications-things-sdk-api

after creating new project, select template and then go on as the following image.

As shown in the below figure, an skeleton code corresponding to capability is created.

Next, let's put source code in the area of "TODO".
>### Define Privilieges for IO
>Special authority called "priviliege" is required to control peripherals such as SPI, PWM, I2C, and GPIO, etc. in Tizen development environemnt.
This can be done by adding **peripheralio** to **tizen-manifest.xml** file. So, let's declare privilieges like the below.

And add include **peripheral_io.h** in source file for using peripheral IO API.
Let device application for this sensor be "**Device App**".
DeviceApp sources consists of roughly three parts like:
* **operation handling code**
This is for main functions to process IOT device operation and handles from/to cloud.
* **capability handling code**
This is for interaction with IoT cloud, SmartThings.
* **resource handling code**
This is for peripheral device control such as light sensor, ADC, ..., etc.
Here is described about these source code.
>**Important Notice**
You can refer full source code in this [link](https://review.tizen.org/gerrit/#/c/apps/native/distance-checker/+/198171/).
These source codes were created in the Tizen 5.0 environment and should be compiled with the Tizen 5.0 SDK.
### Implement operation handling code
This handling code used for processing and handling **distance sensor** working with SmartThings cloud. The entry point of application, ***main()*** is implemented on **distance-checker.c** in the top of source tree.
**distance-checker.c** does initialize, process and control the resource datas for distance sensor, and also initalize the master for SmartThings connection state and build up interface with SmartThings Cloud as well.
Let's trace source code made.
**distance-checker.c** | Implement major handler routine
Special header files are required to use SmartThings API like the below.
```c
#include <service_app.h>
#include "smartthings.h"
#include "smartthings_resource.h"
#include "smartthings_payload.h"
```
The **service_app.h** header file defines a function prototype used for handling service with SmartThings application.
Please refer to the information of **service_app.h** header file on SDK more detail.
The ***smartthings_resource.h*** file on **INC** directory defines resource API functions for handling resource datas and ***smartthings_payload.h*** file does data array type for payload datas in SmartThings stack level.
SmartThings support callback for handling GET request and SET(POST) request. And, it should be registered when initialize application.
In addition to header file for SmartThings API, **log.h** header is for log display to debug.
"**Ecore.h**" is defined to use Tizen timer and peripheral_io.h is for using peripheral_io API.
```c
#include "log.h"
#include <Ecore.h>
#include <peripheral_io.h>
```
First, it defines constant values and macros to handle distance sensor.
```c
#define VALUE_STR_LEN_MAX 32
#define EVENT_INTERVAL_SECOND 0.2f // periodic sensor event timer
#define MIN_RANGE 30 // Minimum distance range (Cm)
#define MAX_RANGE 120 // Maximum distance range (Cm)
#define GREEN_LED 129 // GPIO_129
#define RED_LED 128 // GPIO_128
#define LED_ON 1 // High
#define LED_OFF 0 // Low
#define THING_RESOURCE_FILE_NAME "resource.json"
```
The "mutex" variable used to handle thread locking.
```c
static pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER;
#define MUTEX_LOCK pthread_mutex_lock(&mutex_lock)
#define MUTEX_UNLOCK pthread_mutex_unlock(&mutex_lock)
```
Let’s look at this main source codes.
The ***main()*** function in this file is entry point of Tizen application. This function define event_callback and register callback with ***service_app_main()*** API.
```c
int service_app_main(int argc, char **argv, service_app_lifecycle_callback_s *callback, void *user_data);
```
***service_app_main()*** API is the main entry point of the Tizen service application defined with callback and user data. Generally, this API call at the entry point of application like as main() function.
```c
int main(int argc, char *argv[])
{
service_app_lifecycle_callback_s event_callback;
event_callback.create = service_app_create;
event_callback.terminate = service_app_terminate;
event_callback.app_control = service_app_control;
return service_app_main(argc, argv, &event_callback, NULL);
}
```
The "service_app_lifecycle_callback_s" structure type containing the set of callback for handling application events.
```c
typedef struct {
service_app_create_cb create; /**< This callback function is called at the start of the application. */
service_app_terminate_cb terminate; /**< This callback function is called once after the main loop of the application exits. */
service_app_control_cb app_control; /**< This callback function is called when another application sends the launch request to the application. */
} service_app_lifecycle_callback_s;
```
The each callback must be implemented for things service operation.
```c
static bool service_app_create(void *user_data)
{
bool ret = true;
init_mutex();
if (resource_open_led(GREEN_LED, &green_led_h) != 0) {
_E("GREEN LED resource open failed");
}
if (resource_open_led(RED_LED, &red_led_h) != 0) {
_E("RED LED resource open failed");
}
distance_sensor_event_timer = ecore_timer_add(EVENT_INTERVAL_SECOND, _distance_sensor_interval_event_cb, NULL);
if (!distance_sensor_event_timer) {
_E("Failed to add distance_sensor_event_timer");
ret = false;
}
return ret;
}
static void service_app_terminate(void *user_data)
{
// clear event timer resource
clear_timer_resource();
// clear GPIO resource
resource_close_led(green_led_h);
resource_close_led(red_led_h);
// clear distance sensor resource
resource_close_distance_sensor();
// deinit mutex resource
deinit_mutex();
}
static void service_app_control(app_control_h app_control, void *user_data)
{
if (app_control == NULL) {
_E("app_control is NULL");
return;
}
init_master_app();
init_resource_app();
}
```
The event timer callback ***_distance_sensor_interval_event_cb*** will read and save sensor values and notify ready to send values to cloud.
```c
/*
* timer event callback function
* read distance sensor value from distance sensor
* save sensor value and check for value is in MIN ~ MAX range
* if value is detected, then update presence status
*/
static Eina_Bool _distance_sensor_interval_event_cb(void *data)
{
uint16_t sensor_value;
int ret = 0;
// read sensor value
ret = resource_read_distance_sensor(&sensor_value);
if (ret != 0) {
_E("invalid sensor value");
return ECORE_CALLBACK_RENEW;
} else {
if (st_things_status != SMARTTHINGS_STATUS_REGISTERED_TO_CLOUD) {
return ECORE_CALLBACK_RENEW;
}
if (!st_handle) {
_D("st_handle is NULL");
return ECORE_CALLBACK_RENEW;
}
// save sensor value
set_sensor_value(sensor_value);
update_sensor_value();
#ifndef _DEBUG_PRINT_
struct timeval tv;
gettimeofday(&tv, NULL);
_I("[%d.%06d] distance : %d Cm", tv.tv_sec, tv.tv_usec, sensor_value);
#endif
// check if value is within MIN ~ MAX range
if ((sensor_value > MIN_RANGE) && (sensor_value < MAX_RANGE)) {
update_presence_status(true);
} else {
update_presence_status(false);
}
}
// reset event timer periodic
return ECORE_CALLBACK_RENEW;
}
void clear_timer_resource(void)
{
_I("clear_timer_resource...");
if (distance_sensor_event_timer) {
ecore_timer_del(distance_sensor_event_timer);
distance_sensor_event_timer = NULL;
}
}
```
***update_sensor_value()*** function sends measured distance value to cloud according to ***get_switch_status()*** .
***get_switch_status()*** read distance sensor on/off status and ***set_switch_status()*** set this sensor on/off state.
***update_presence_status()*** updates presence status and LED control. When presence detected, this sets LEDs - Red : ON, Green : OFF, When leaved, Red : OFF, Green : ON.
```c
static void update_sensor_value(void)
{
bool status;
int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
status = get_switch_status();
if (status == true) {
uint16_t sensor_value = get_sensor_value();
#ifndef _DEBUG_PRINT_
struct timeval tv;
gettimeofday(&tv, NULL);
_I("[%d.%06d] distance : %d Cm", tv.tv_sec, tv.tv_usec, sensor_value);
#endif
smartthings_payload_h resp_payload = NULL;
// send notification to cloud server
error = smartthings_payload_create(&resp_payload);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE || !resp_payload) {
_E("smartthings_payload_create() failed, [%d]", error);
return;
}
error = smartthings_payload_set_int(resp_payload, PROP_ILLUMINANCE, sensor_value);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_payload_set_int() failed, [%d]", error);
return;
}
error = smartthings_resource_notify(st_handle, RES_CAPABILITY_ILLUMINANCEMEASUREMENT_MAIN_0, resp_payload);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_resource_notify() failed, [%d]", error);
return;
}
if (smartthings_payload_destroy(resp_payload)) {
_E("smartthings_payload_destroy() failed");
return;
}
}
}
/*
* update presence status
* On presence detected, set Red led:ON, Green led:OFF
* On leace status, set Red led:OFF, Green led:ON
*/
static void update_presence_status(bool status)
{
static bool present = false;
int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
if (present == status) {
// same status, do nothing
return;
}
if (status == true) {
//_I("Arrive - Red:ON, Green:OFF");
present = true;
set_presence_status(present);
// set presence detected status
resource_write_led(green_led_h, LED_OFF);
resource_write_led(red_led_h, LED_ON);
}
else {
//_I("Leave - Red:OFF, Green:ON");
present = false;
set_presence_status(present);
// clear presence detected status
resource_write_led(green_led_h, LED_ON);
resource_write_led(red_led_h, LED_OFF);
}
if (g_switch_status == true) {
smartthings_payload_h resp_payload = NULL;
smartthings_payload_create(&resp_payload);
if (!resp_payload) {
_E("Response payload is NULL");
return;
}
// create response payload
error = smartthings_payload_create(&resp_payload);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE || !resp_payload) {
_E("smartthings_payload_create() failed, [%d]", error);
return;
}
// set response data into payload
error = smartthings_payload_set_bool(resp_payload, PROP_VALUE, status);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_payload_set_bool() failed, [%d]", error);
return;
}
// send notification to cloud server
error = smartthings_resource_notify(st_handle, RES_CAPABILITY_PRESENCESENSOR_MAIN_0, resp_payload);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_resource_notify() failed, [%d]", error);
return;
}
if (smartthings_payload_destroy(resp_payload)) {
_E("smartthings_payload_destroy() failed");
return;
}
_I("notify presence status : %d", status);
}
}
bool get_switch_status(void)
{
bool status = false;
MUTEX_LOCK;
status = g_switch_status;
MUTEX_UNLOCK;
return status;
}
void set_switch_status(bool status)
{
MUTEX_LOCK;
g_switch_status = status;
MUTEX_UNLOCK;
}
void get_presence_status(bool *status)
{
MUTEX_LOCK;
*status = g_presence_status;
MUTEX_UNLOCK;
}
static void set_presence_status(bool status)
{
MUTEX_LOCK;
g_presence_status = status;
MUTEX_UNLOCK;
}
```
And, ***get_sensor_value()*** reads sensor datas and ***set_sensor_value()*** writes it.
```c
uint16_t get_sensor_value(void)
{
uint16_t value = 0;
MUTEX_LOCK;
value = g_distance;
MUTEX_UNLOCK;
return value;
}
static void set_sensor_value(uint16_t value)
{
MUTEX_LOCK;
g_distance = value;
MUTEX_UNLOCK;
}
```
***init_resource_app()*** called by ***service_app_control()*** is a resource API to control resource datas from SmartThings App. ***smartthings_resource_initialize()*** API in ***init_resource_app()*** fuction start initializing resource status and register ***smartthings_resource_set_request_cb()*** callback. ***smartthings_resource_set_request_cb()*** includes connection status check functions and resource SET/GET interface functions by URI informations to response resource request from SmartThings App.
If the resource status is changed, responses be sent by ***smartthings_resource_send_response()*** and notification by ***smartthings_resource_notify()*** as request.
***handle_get_request_on_resource_capability_xxxx_main_0()*** callback is a request function to get resource data from SmartThings App and ***handle_set_request_on_resource_capability_xxxx_main_0()*** callback is to set it up according to uri information in ***_request_cb()*** called by ***smartthings_resource_set_request_cb()*** .
***handle_get_request_on_resource_capability_switch_main_0()*** / ***handle_set_request_on_resource_capability_switch_main_0()*** ,
***handle_get_request_on_resource_capability_illuminancemeasurement_main_0()*** and ***handle_get_request_on_resource_capability_presencesensor_main_0()*** , these handle callback functions included in ***_request_cb*** will be explained on **capability handling code** step below.
```c
int init_resource_app()
{
START;
if (is_resource_init) {
_I("Already initialized!");
return 0;
}
if (smartthings_resource_initialize(&st_handle, _resource_connection_status_cb, NULL) != 0) {
_E("smartthings_resource_initialize() is failed");
goto _out;
}
is_resource_init = true;
END;
return 0;
_out :
END;
return -1;
}
void _request_cb(smartthings_resource_h st_h, int req_id, const char *uri, smartthings_resource_req_type_e req_type,
smartthings_payload_h payload, void *user_data)
{
smartthings_payload_h resp_payload = NULL;
smartthings_payload_create(&resp_payload);
if (!resp_payload) {
_E("Response payload is NULL");
return;
}
bool result = false;
if (req_type == SMARTTHINGS_RESOURCE_REQUEST_GET) {
if (0 == strncmp(uri, RES_CAPABILITY_SWITCH_MAIN_0, strlen(RES_CAPABILITY_SWITCH_MAIN_0))) {
result = handle_get_request_on_resource_capability_switch_main_0(resp_payload, user_data);
}
if (0 == strncmp(uri, RES_CAPABILITY_ILLUMINANCEMEASUREMENT_MAIN_0, strlen(RES_CAPABILITY_ILLUMINANCEMEASUREMENT_MAIN_0))) {
result = handle_get_request_on_resource_capability_illuminancemeasurement_main_0(resp_payload, user_data);
}
if (0 == strncmp(uri, RES_CAPABILITY_PRESENCESENSOR_MAIN_0, strlen(RES_CAPABILITY_PRESENCESENSOR_MAIN_0))) {
result = handle_get_request_on_resource_capability_presencesensor_main_0(resp_payload, user_data);
}
} else if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
if (0 == strncmp(uri, RES_CAPABILITY_SWITCH_MAIN_0, strlen(RES_CAPABILITY_SWITCH_MAIN_0))) {
result = handle_set_request_on_resource_capability_switch_main_0(payload, resp_payload, user_data);
}
} else {
_E("Invalid request type");
smartthings_payload_destroy(resp_payload);
return;
}
int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
error = smartthings_resource_send_response(st_h, req_id, uri, resp_payload, result);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
smartthings_payload_destroy(resp_payload);
_E("smartthings_resource_send_response() failed, err=[%d]", error);
return;
}
if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
error = smartthings_resource_notify(st_h, uri, resp_payload);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_resource_notify() failed, err=[%d]", error);
}
}
if (smartthings_payload_destroy(resp_payload) != 0) {
_E("smartthings_payload_destroy failed");
}
return;
}
static void _resource_connection_status_cb(smartthings_resource_h handle, smartthings_resource_connection_status_e status, void *user_data)
{
START;
if (status == SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED) {
if (smartthings_resource_set_request_cb(st_handle, _request_cb, NULL) != 0) {
_E("smartthings_resource_set_request_cb() is failed");
return;
}
} else {
_I("connection failed, status=[%d]", status);
}
END;
return;
}
```
capabilities handle resources by req_msg->resource_uri and the three capabilities that used for handling distance sensor datas are defined as the following.
```c
static const char *RES_CAPABILITY_PRESENCESENSOR_MAIN_0 = "/capability/presenceSensor/main/0";
static const char *RES_CAPABILITY_SWITCH_MAIN_0 = "/capability/switch/main/0";
static const char *RES_CAPABILITY_ILLUMINANCEMEASUREMENT_MAIN_0 = "/capability/illuminanceMeasurement/main/0";
```
When array type's resource payload datas are transfered, it should be added the following codes.
The following is to start sendng payload datas.
```c
smartthings_payload_h resp_payload = NULL;
smartthings_payload_create(&resp_payload);
```
After finishing payload transfer, please release it.
```c
smartthings_payload_destroy(resp_payload)
```
The following is subroutine for ***init_resource_app()*** , resource API.
```c
void _send_response_result_cb(smartthings_resource_error_e result, void *user_data)
{
_D("app_control reply callback for send_response : result=[%d]", result);
}
void _notify_result_cb(smartthings_resource_error_e result, void *user_data)
{
_D("app_control reply callback for notify : result=[%d]", result);
}
int deinit_resource_app()
{
START;
if (!st_handle)
return 0;
smartthings_resource_unset_request_cb(st_handle);
if (smartthings_resource_deinitialize(st_handle) != 0)
return -1;
is_resource_init = false;
END;
return 0;
}
```
***init_master_app()*** called by ***service_app_control()*** is a master API to connect to SmartThings Cloud with an account.
***_things_connection_status_cb()*** called by ***smartthings_initialize()*** fuction register a list of callback functions like the below with initializing.
- **smartthings_set_certificate_file()**
- **smartthings_set_user_confirm_cb()** : a callback to confirm ownership transfer by user
- **smartthings_set_reset_confirm_cb()** : a callback to confirm reset by user
- **smartthings_set_reset_result_cb()** : a callback to confirm reset result by user
- **smartthings_set_status_changed_cb()** : a callback to check status changed
- **smartthings_start()** : a callback to start agent
- **smartthings_get_easysetup_status()**
- **smartthings_start_easysetup()**
And some additional SmartThings handling callback is implemented by requirement. The additional handling callback is used for handle reset request, return reset result, ownership transfer request and things status change request from things cloud.
```c
int init_master_app()
{
START;
if (is_init) {
_I("Already initialized!");
END;
return 0;
}
if (smartthings_initialize(&st_h, _things_connection_status_cb, NULL) != 0) {
_E("smartthings_initialize() is failed");
goto _out;
}
is_init = true;
END;
return 0;
_out :
END;
return -1;
}
```
The following is subroutine for ***init_master_app()*** , master API.
```c
void _user_confirm_cb(smartthings_h handle, void *user_data)
{
START;
if (smartthings_send_user_confirm(handle, true) != 0)
_E("smartthings_send_user_confirm() is failed");
END;
return;
}
void _reset_confirm_cb(smartthings_h handle, void *user_data)
{
START;
if (smartthings_send_reset_confirm(handle, true) != 0)
_E("smartthings_send_reset_confirm() is failed");
END;
return;
}
static void _reset_result_cb(smartthings_h handle, bool result, void *user_data)
{
START;
_I("reset result = [%d]", result);
END;
return;
}
static void _thing_status_cb(smartthings_h handle, smartthings_status_e status, void *user_data)
{
START;
_D("Received status changed cb : status = [%d]", status);
st_things_status = status;
switch (status) {
case SMARTTHINGS_STATUS_NOT_READY:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_NOT_READY");
break;
case SMARTTHINGS_STATUS_INIT:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_INIT");
break;
case SMARTTHINGS_STATUS_ES_STARTED:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_ES_STARTED");
break;
case SMARTTHINGS_STATUS_ES_DONE:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_ES_DONE");
break;
case SMARTTHINGS_STATUS_ES_FAILED_ON_OWNERSHIP_TRANSFER:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_ES_FAILED_ON_OWNERSHIP_TRANSFER");
break;
case SMARTTHINGS_STATUS_CONNECTING_TO_AP:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_CONNECTING_TO_AP");
break;
case SMARTTHINGS_STATUS_CONNECTED_TO_AP:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_CONNECTED_TO_AP");
break;
case SMARTTHINGS_STATUS_CONNECTING_TO_AP_FAILED:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_CONNECTING_TO_AP_FAILED");
break;
case SMARTTHINGS_STATUS_REGISTERING_TO_CLOUD:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_REGISTERING_TO_CLOUD");
break;
case SMARTTHINGS_STATUS_REGISTERED_TO_CLOUD:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_REGISTERED_TO_CLOUD");
break;
case SMARTTHINGS_STATUS_REGISTERING_FAILED_ON_SIGN_IN:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_REGISTERING_FAILED_ON_SIGN_IN");
break;
case SMARTTHINGS_STATUS_REGISTERING_FAILED_ON_PUB_RES:
_I("status: [%d] [%s]", status, "SMARTTHINGS_STATUS_REGISTERING_FAILED_ON_PUB_RES");
break;
default:
_E("status: [%d][%s]", status, "Unknown Status");
break;
}
END;
return;
}
static void _things_connection_status_cb(smartthings_h handle, smartthings_connection_status_e status, void *user_data)
{
START;
_D("Received connection status changed cb : status = [%d]", status);
if (status == SMARTTHINGS_CONNECTION_STATUS_CONNECTED) {
const char* dev_name = "IoT Test Device";
int wifi_mode = SMARTTHINGS_WIFI_MODE_11B | SMARTTHINGS_WIFI_MODE_11G | SMARTTHINGS_WIFI_MODE_11N;
int wifi_freq = SMARTTHINGS_WIFI_FREQ_24G | SMARTTHINGS_WIFI_FREQ_5G;
if (smartthings_set_device_property(handle, dev_name, wifi_mode, wifi_freq) != 0) {
_E("smartthings_initialize() is failed");
return;
}
if (smartthings_set_certificate_file(handle, "certificate.pem", "privatekey.der") != 0) {
_E("smartthings_set_certificate_file() is failed");
return;
}
if (smartthings_set_user_confirm_cb(st_h, _user_confirm_cb, NULL) != 0) {
_E("smartthings_set_user_confirm_cb() is failed");
return;
}
if (smartthings_set_reset_confirm_cb(handle, _reset_confirm_cb, NULL) != 0) {
_E("smartthings_set_reset_confirm_cb() is failed");
return;
}
if (smartthings_set_reset_result_cb(handle, _reset_result_cb, NULL) != 0) {
_E("smartthings_set_reset_confirm_cb() is failed");
return;
}
if (smartthings_set_status_changed_cb(handle, _thing_status_cb, NULL) != 0) {
_E("smartthings_set_status_changed_callback() is failed");
return;
}
if (smartthings_start(handle) != 0) {
_E("smartthings_start() is failed");
return;
}
bool is_es_completed = false;
if (smartthings_get_easysetup_status(handle, &is_es_completed) != 0) {
_E("smartthings_get_easysetup_status() is failed");
return;
}
if (is_es_completed == true) {
_I("Easysetup is already done");
return;
}
if (smartthings_start_easysetup(handle) != 0) {
_E("smartthings_start_easysetup() is failed");
return;
}
} else {
_E("connection failed, status=[%d]", status);
}
END;
return;
}
int deinit_master_app()
{
START;
is_init = false;
if (!st_h) {
_I("handle is already NULL");
END;
return 0;
}
smartthings_unset_user_confirm_cb(st_h);
smartthings_unset_reset_confirm_cb(st_h);
smartthings_unset_reset_result_cb(st_h);
smartthings_unset_status_changed_cb(st_h);
if (smartthings_deinitialize(st_h) != 0) {
_E("smartthings_deinitialize() is failed");
END;
return -1;
}
END;
return 0;
}
```
This code defines constant like the below:
```c
static const char *PROP_ILLUMINANCE = "illuminance";
static const char *PROP_VALUE = "value";
```
### Implement capability handling code
Let's add capability handling codes in **Device App**.
As mentioned before, we use three capabilities. So, three files are created:
* **capability_switch.c**
* **capability_illuminancemeasurement.c**
* **capability_presencesensor**
Here is described about each source code.
**capability_switch.c** | Turn on and off for distance sensor operation
This is for control to enable or disable blind operation by SmartThings App through cloud. ***handle_get_request_on_resource_capability_switch_main_0()*** callback is called from ***_request_cb()*** in **distance-checker.c** file when the resource URI of request message is “**RES_CAPABILITY_SWITCH_MAIN_0**” .
```c
...
if (req_type == SMARTTHINGS_RESOURCE_REQUEST_GET) {
if (0 == strncmp(uri, RES_CAPABILITY_SWITCH, strlen(RES_CAPABILITY_SWITCH))) {
result = handle_get_request_on_resource_capability_switch_main_0(resp_payload, user_data);
}
...
} else if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
if (0 == strncmp(uri, RES_CAPABILITY_SWITCH, strlen(RES_CAPABILITY_SWITCH))) {
result = handle_set_request_on_resource_capability_switch_main_0(payload, resp_payload, user_data);
}
...
}
...
```
***handle_get_request_on_resource_capability_switch_main_0()*** callback returns power status and ***handle_get_request_on_resource_capability_switch_main_0()*** callback sets sensor to enable or disable state and notifys it to SmartThings cloud.
```c
bool handle_get_request_on_resource_capability_switch_main_0(smartthings_payload_h resp_payload, void *user_data)
{
bool switch_status;
int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
switch_status = get_switch_status();
if (switch_status == true) {
error = smartthings_payload_set_string(resp_payload, PROP_POWER, VALUE_SWITCH_ON);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_payload_set_string() failed, [%d]", error);
return false;
}
} else {
error = smartthings_payload_set_string(resp_payload, PROP_POWER, VALUE_SWITCH_OFF);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_payload_set_string() failed, [%d]", error);
return false;
}
}
return true;
}
bool handle_set_request_on_resource_capability_switch_main_0(smartthings_payload_h payload, smartthings_payload_h resp_payload, void *user_data)
{
char *str_value = NULL;
int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
error = smartthings_payload_get_string(payload, PROP_POWER, &str_value);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_payload_get_string() failed, [%d]", error);
return false;
}
/* check validation */
if ((0 != strncmp(str_value, VALUE_SWITCH_ON, strlen(VALUE_SWITCH_ON)))
&& (0 != strncmp(str_value, VALUE_SWITCH_OFF, strlen(VALUE_SWITCH_OFF)))) {
_E("Not supported value!!");
free(str_value);
return false;
}
if (0 != strncmp(str_value, g_switch, strlen(g_switch))) {
strncpy(g_switch, str_value, VALUE_STR_LEN_MAX);
if (0 == strncmp(g_switch, VALUE_SWITCH_ON, strlen(VALUE_SWITCH_ON))) {
set_switch_status(true);
} else {
set_switch_status(false);
}
}
free(str_value);
error = smartthings_payload_set_string(resp_payload, PROP_POWER, g_switch);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_payload_set_string() failed, [%d]", error);
return false;
}
return true;
}
```
The variables that used to handle in the routine define as the followings:
```c
#define VALUE_STR_LEN_MAX 32
static const char *PROP_POWER = "power";
static const char *VALUE_SWITCH_ON = "on";
static const char *VALUE_SWITCH_OFF = "off";
static char g_switch[VALUE_STR_LEN_MAX] = "off";
```
**capability_illuminancemeasurement.c** | measure and update distance sensor value
This is codes to measure and update distance sensor value by cloud request.
***handle_get_request_on_resource_capability_illuminancemeasurement_main_0()*** callback in this source file is called from ***_request_cb()*** in **distance-checker.c** file when the resource URI of request message is **RES_CAPABILITY_ILLUMINANCEMEASUREMENT_MAIN_0** .
The following is source code how ***_request_cb()*** call ***handle_get_request_on_resource_capability_illuminancemeasurement_main_0()*** callback in **distance-checker.c** file.
```c
...
if (req_type == SMARTTHINGS_RESOURCE_REQUEST_GET) {
...
if (0 == strncmp(uri, RES_CAPABILITY_ILLUMINANCEMEASUREMENT_MAIN_0, strlen(RES_CAPABILITY_ILLUMINANCEMEASUREMENT_MAIN_0))) {
result = handle_get_request_on_resource_capability_illuminancemeasurement_main_0(resp_payload, user_data);
}
...
}
...
```
***handle_get_request_on_resource_capability_illuminancemeasurement_main_0()*** callback sends sensor values to cloud.
```c
bool handle_get_request_on_resource_capability_illuminancemeasurement_main_0(smartthings_payload_h resp_payload, void *user_data)
{
uint16_t sensor_value;
int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
// get distance sensor value
sensor_value = get_sensor_value();
// set sensor value
error = smartthings_payload_set_int(resp_payload, PROP_ILLUMINANCE, sensor_value);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_payload_set_int() failed, [%d]", error);
return false;
}
return true;
}
```
This routine includes one constant definition to handle data:
```c
static const char *PROP_ILLUMINANCE = "illuminance";
```
**capability_presencesensor.c** | Detecting pre-defined level
This code is to detect whether an data is valid or not by SmartThings App through cloud. ***handle_get_request_on_resource_capability_presencesensor_main_0()*** callback is called by ***_request_cb()*** in **distance-checker.c** file when the resource URI of request message is **RES_CAPABILITY_PRESENCESENSOR_MAIN_0** .
```c
if (req_type == SMARTTHINGS_RESOURCE_REQUEST_GET) {
...
if (0 == strncmp(uri, RES_CAPABILITY_PRESENCESENSOR_MAIN_0, strlen(RES_CAPABILITY_PRESENCESENSOR_MAIN_0))) {
result = handle_get_request_on_resource_capability_presencesensor_main_0(resp_payload, user_data);
}
...
```
***handle_get_request_on_resource_capability_presencesensor_main_0()*** callback returns presence state value by bool type to cloud.
```c
bool handle_get_request_on_resource_capability_presencesensor_main_0(smartthings_payload_h resp_payload, void *user_data)
{
bool presence_status;
int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
get_presence_status(&presence_status);
error = smartthings_payload_set_bool(resp_payload, PROP_VALUE, presence_status);
if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
_E("smartthings_payload_set_bool() failed, [%d]", error);
return false;
}
return true;
}
```
Here is added constant define:
```c
static const char *PROP_VALUE = "value";
```
### Implement resource handling code
To work distance sensor device have to be added resource handling code.
Two files are created, one for this sensor and the other for LED to check detection status.
* **resource_distance_sensor.c** : for measured distance sensor value.
* **resource_led.c** : for checking presence status.
**resource_distance_sensor.c** file is a code to get the value from distance sensor device.
I choose I2C interface for interfacing with distance sensor. So, this means need to use peripheral interface API.
Before looking at these sources, let's see about how to set and control I2C API.
The below is the APIs for the I2C interface, among the various peripheral I/O APIs Tizen provides.
```c
/* Open & Close interface */
int peripheral_i2c_open(int bus, int address, peripheral_i2c_h *i2c)
int peripheral_i2c_close(peripheral_i2c_h *i2c);
/* Transfer data */
int peripheral_i2c_read(peripheral_i2c_h i2c, uint8_t *data, uint32_t length)
int peripheral_i2c_write(peripheral_i2c_h i2c, uint8_t *data, uint32_t length)
```
To open a I2C handle, use the **peripheral_i2c_open** function:
The bus and address parameters required for this function must be set according to the following.
| Pin name | Bus number(parameter 1) |
|:----------:|:-------------------:|
| I2C1_SDA, I2C1_SCL | 1 |
And we can get I2C address from SRF02 datasheet.
So, this parameter value will be **bus**=1, **address**=0x70 for eagleyes board.

To close a I2C handle that is no longer used, use the **peripheral_i2c_close()** function:
>**Important Notice**
For more information about **I2C** for Tizen Peripheral I/O Native API, please click [here](
https://developer.tizen.org/ko/development/iot-preview/iot-apis/tizen-peripheral-io-native-api/i%C2%B2c)
let's get back to source code trace.
First, we need to include some header files to handle distance sensor.
```c
#include <unistd.h>
#include <peripheral_io.h>
#include "log.h"
```
We must define I2C bus number and device information. Using I2C API based on Tizen and SRF02 device information as described on the above, we can write code to obtain I2C input data of distance sensor. The I2C bus number depend on hardware(Eagleye530) and pin configuration.
~~~c
#define ARTIK_I2C_BUS 1 // ARTIK I2C BUS
#define SRF02_ADDR 0x70 // Address of the SRF02 shifted right one bit
~~~
We must open the I2C interface using Tizen peripheral I/O API prior to use it and close it after finish using the bus.
I2C open API, ***resource_open_i2c_handle()***, is called by ***service_app_control()*** when service application creates and I2C close API, ***resource_close_i2c_handle()*** is called by ***service_app_terminate()*** when service application terminates . The distance sensor value is read by event timer each 200 miliseconds.
***resource_read_distance_sensor()*** by ***service_app_create()*** and ***resource_close_distance_sensor()*** by ***service_app_terminate()*** are called in **distance-checker.c** file.
~~~c
static int _open_distance_sensor(void)
{
int ret;
// open i2c handle for I2C read/write
if ((ret = peripheral_i2c_open(ARTIK_I2C_BUS, SRF02_ADDR, &distance_sensor_h)) != 0 ) {
_E("peripheral_i2c_open() failed!![%d]", ret);
return ret;
}
return ret;
}
int resource_read_distance_sensor(uint16_t *out_value)
{
int ret = PERIPHERAL_ERROR_NONE;
unsigned char buf[10] = { 0, }; // Buffer for data being read/ written on the i2c bus
uint16_t range;
if (distance_sensor_h == NULL) {
// open i2c handle for I2C read/write
if ((ret = _open_distance_sensor()) != PERIPHERAL_ERROR_NONE ) {
_E("peripheral_i2c_open() failed!![%d]", ret);
return ret;
}
}
buf[0] = 0; // Commands for performing a ranging
buf[1] = 0x51; // Real Ranging Mode - Result in centimeters
// write mode command to sensor
if ((ret = peripheral_i2c_write(distance_sensor_h, buf, 2)) != PERIPHERAL_ERROR_NONE) {
_E("peripheral_i2c_write() failed!![%d]", ret);
return ret;
}
usleep(80000); // This sleep waits for the ping to come back
buf[0] = 0; // This is the register we wish to read from
// Send the register to read from
if ((ret = peripheral_i2c_write(distance_sensor_h, buf, 1)) != PERIPHERAL_ERROR_NONE) {
_E("peripheral_i2c_write() failed!![%d]", ret);
return ret;
}
// // Read back data into buf[]
if ((ret = peripheral_i2c_read(distance_sensor_h, buf, 6)) != PERIPHERAL_ERROR_NONE) {
_E("peripheral_i2c_read() failed!![%d]", ret);
return ret;
} else {
/*
* Location Read Write
* 0 Software Revision Command Register // If this is 255, then the ping has not yet returned
* 1 Unused (reads 0x80) N/A
* 2 Range High Byte N/A
* 3 Range Low Byte N/A
* 4 Autotune N/A
* Minimum - High Byte
* 5 Autotune N/A
* Minimum - Low Byte
*/
range = (buf[2] << 8) + buf[3]; // Calculate range as a word value
}
#ifdef DEBUG
_I("Range : %u Cm", range);
#endif
*out_value = range;
return ret;
}
int resource_close_distance_sensor(void)
{
int ret = PERIPHERAL_ERROR_NONE;
if (distance_sensor_h != NULL) {
// close i2c handle
if ((ret = peripheral_i2c_close(distance_sensor_h)) != 0 ) {
_E("peripheral_i2c_close() failed!![%d]", ret);
}
distance_sensor_h = NULL;
}
_I("resource_close_distance_sensor...");
return ret;
}
~~~
#### resource_led.c
I add function to present distance detection indicator using LED by GPIO. So, we need to look at GPIO API.
Let's see about how to set and control GPIO API. The below is the APIs for the GPIO interface, among the various peripheral I/O APIs Tizen provides.
```c
/* Open & Close interface */
int peripheral_gpio_open (int gpio_pin, peripheral_gpio_h *gpio)
int peripheral_gpio_close (peripheral_gpio_h gpio)
/* Transfer data */
int peripheral_gpio_read (peripheral_gpio_h gpio, uint32_t *value)
int peripheral_gpio_write (peripheral_gpio_h gpio, uint32_t value)
int peripheral_gpio_set_direction (peripheral_gpio_h gpio, peripheral_gpio_direction_e direction)
```
>**Important Notice**
For more information about **GPIO** for Tizen Peripheral I/O Native API, please click [here](
https://developer.tizen.org/ko/development/iot-preview/iot-apis/tizen-peripheral-io-native-api/gpio)
To open a GPIO handle, use the **peripheral_gpio_open** function:
Eagleye Board provides many GPIO ports. GPIO pin parameter required for this function must be set according to the following.
| Pin name | Pin (parameter 1) | Pin name | Pin (parameter 1) |
|:----------:|:-------------------:|:----------:|:-------------------:|
| GPIO0 | 128 | GPIO1 | 129 |
| GPIO2 | 130 | GPIO3 | 46 |
| GPIO4 | 14 | GPIO5 | 41 |
| GPIO6 | 25 | GPIO7 | 0 |
| GPIO8 | 26 | GPIO9 | 27 |
But, I will just 2 GPIO(GPIO0, GPIO1) for LED.
let's return source code and define it as the following source code.
~~~c
#define GREEN_LED 129 // GPIO_129
#define RED_LED 128 // GPIO_128
/* distance-checker.c */
~~~
To close a I2C handle that is no longer used, use the ***peripheral_i2c_close()*** function:
And insert some header files to handle distance sensor on the top of code.
```c
#include <unistd.h>
#include <peripheral_io.h>
#include "log.h"
```
We must open GPIO interface using Tizen peripheral I/O API prior to use it and close it after finish using the bus.
~~~c
int resource_close_led(peripheral_gpio_h handle)
{
int ret = PERIPHERAL_ERROR_NONE;
_I("LED is finishing...");
ret = peripheral_gpio_close(handle);
if (ret != PERIPHERAL_ERROR_NONE) {
_E("peripheral_gpio_close failed");
}
return ret;
}
int resource_open_led(int gpio_pin, peripheral_gpio_h *handle)
{
int ret = PERIPHERAL_ERROR_NONE;
_I("LED(gpio_pin:%d) is opening...", gpio_pin);
ret = peripheral_gpio_open(gpio_pin, handle);
if (ret != PERIPHERAL_ERROR_NONE) {
_E("peripheral_gpio_open failed, ret=[%d]", ret);
}
ret = peripheral_gpio_set_direction(*handle, PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW);
if (ret != PERIPHERAL_ERROR_NONE) {
_E("peripheral_gpio_set_direction failed, ret=[%d]", ret);
}
return ret;
}
~~~
GPIO open API, ***resource_open_gpio_handle()***, is called by ***service_app_control()*** when service application creates and GPIO close API, ***resource_close_gpio_handle()*** is called by ***service_app_terminate()*** when service application terminates .
This code is from resource_led file.
The distance sensor LED status is updated when detecting on presence, Red led set to ON state, Green led set to OFF state, on leave status, set to Red led : OFF, Green led : ON
~~~c
int resource_write_led(peripheral_gpio_h handle, int write_value)
{
int ret = PERIPHERAL_ERROR_NONE;
if (!handle) {
_E("peripheral_gpio_open failed, ret=[%d]", ret);
return -1;
}
ret = peripheral_gpio_write(handle, write_value);
if (ret != PERIPHERAL_ERROR_NONE) {
_E("peripheral_gpio_write failed, ret=[%d]", ret);
return -1;
}
//_I("LED Value : %s", write_value ? "ON":"OFF");
return 0;
}
~~~
*****
# Implement ST Plugin
SmartThings app is able to use a default plugin for IoT devices that simply use predefined capabilities. Therefore, you can directly operate this sensor device without coding already.
But, let us try to implement customized UI for exercise.
We need to review the UI layout. Plugin UI layout was designed considering various information output as the following image.

For customizing the UI of app plugin for distance sensor, I used the JavaScript API for device plugins with HTML, CSS as well.
"+" mark position and distance value will be changed according to detected status.
SmartThings web distributes commonly used icons on plug-in screens.
You can get it here (Samsung_Connect_Icons_All.zip)
https://smartthings.developer.samsung.com/style/resources.html
### Implement plugin handling code
>**Important Notice**
You can download this source code in [here](https://review.tizen.org/gerrit/#/c/apps/native/distance-checker/+/198171/).
and refer to [this](https://smartthings.developer.samsung.com/develop/guides/plugin/overview.html) for howto.
Also you can refer more examples of Plugin source code for Cloud-Connected Device in [here](https://github.com/Samsung/SmartThings).
### Evaluation using simulator with virtual device
you can test a developed plugin using simulator and virtual device before launching physical mobile device.
The below image represent how to test in detail using virtual device.

For more information on testing with Developer Workspace, see here [link 1](https://smartthings.developer.samsung.com/develop/workspace/general-tools/device-plugin-simulator.html) and [link 2](https://smartthings.developer.samsung.com/develop/guides/testing/how-to-test.html).
*****
# Operation Test
### Evaluation using mobile phone with real physical IoT device
For testing in physical mobile phone, you must enable Developer Mode before you can test using the SmartThings app.
The following diagram presents how to add new device.
Note that Device app must be installed and turn on power in target board.

For information on testing with Developer Workspace, see [here](https://smartthings.developer.samsung.com/develop/guides/testing/developer-mode.html).
And refer to the actual test video including the entire sequence in the below.
@[youtube](https://youtu.be/r3mjnfkniAU)
*****
Notice
Are you sure to delete this post?
IOTdevice-RangeCheck
1
0
|
Last modified on January 30, 2019
Craft info. | |
Maker |
![]() |
Status | In Progress |
Period | 2018-10-01 ~ 2018-10-31 |
About This Craft | |
Here is described how to make Light intensity sensor as SmartThings IOT device on Tizen development environment. | |
Making Note