[본 문서는 서울 IoT 센터에서 진행할 교육을 위해 작성된 한글문서입니다.]
[This document is currently written in Korean only for the purpose of being presented in the Seoul IoT tutorial.]
본 강의는 [Smart Motion Light Basic](https://craftroom.tizen.org/smartmotionlight/) 강의에서 이어지는 강의입니다.
# 준비물
:::hw
Board|Eageleye 530s|1|
Board|Motion Sensor|1|HC-SR501|
Board|LED Light|1|
Board|Resistor|1|330 ohm
:::
:::sw
SDK|Tizen Studio|
App|SmartThings|Android App
:::
***
# SmartThings
## SmartThings란?
SmartThings 앱으로 스마트 디바이스를 연결하여 관리 및 제어할 수 있도록 제공되는 IoT 플랫폼
[SmartThings 공식 홈페이지](https://www.smartthings.com/)
[Samsung SmartThings 소개](https://www.samsung.com/sec/apps/smartthings/)
**높은 확장성을 가져 삼성전자의 제품 외에도 다양한 제품군을 지원하며, 타이젠을 통해 보다 쉽게 SmartThings 앱 개발이 가능**
## SmartThings Developers
[SmartThings Developers 홈페이지](https://smartthings.developer.samsung.com/develop/index.html)
### SmartThings Ecosystem
다양한 스마트 기기와 SmartThings App 등이 SmartThings Cloud를 통해 서로 연결되고, 제공되는 SmartThings API를 통해 제어 가능

- **SmartThings App**: 스마트폰 앱을 사용하여 다양한 IoT 기기들에 대한 자동화 설정, 수동 제어 및 알림 설정 등이 가능함
- **SmartThings Devices**: 기기들은 SmartThings Cloud에 직접적(cloud-connected) 혹은 간접적으로(third-party 클라우드와 SmartThings Connecter를 통해) 연결 가능함
- **SmartThings API**: IoT 기기들을 SmartThings Cloud에 연결하고 제어 가능하도록 해줌
- **Automations**: RESTful SmartThings API를 사용한 자동화 설정을 통해 IoT 기기들을 제어하고 알림 등을 받을 수 있음
- **Developer Workspace**: IoT 기기 추가 및 자동화 설정 등을 위한 일련의 도구들을 제공함
### SmartThings App 활용예제
- 아침이 되면 전등과 coffee 머신을 켜주는 앱
- 비가 내리면 창문이 열려있는 지 알림을 띄워주는 앱
### Cloud-connected App

**본 실습에서는 OCF spec에 기반하여 SmartThings Cloud와 직접적으로 통신하는 Cloud-connected Tizen App을 만들어 볼 예정**
***
# Tizen and SmartThings
[Tizen Things SDK API](https://developer.tizen.org/development/iot-extension-sdk/api-guides/things-sdk-api)
[Things SDK API - API Usage](https://developer.tizen.org/development/iot-extension-sdk/api-guides/things-sdk-api/api-usage)
[ST Things SDK API Document](https://developer.tizen.org/dev-guide/things-sdk/index.html)
## Initializing Stack and Callbacks
### 디바이스 초기화
```C
int st_things_set_configuration_prefix_path(const char* ro_path, const char* rw_path);
```
디바이스 설정 파일이 저장되는 경로를 지정
* ro_path: read-only 파일을 저장할 디렉토리 경로
* rw_path: read-write 파일을 저장할 디렉토리 경로
```C
int st_things_initialize(const char *json_path, bool *easysetup_complete);
```
SmartThings와의 연동을 위한 초기화 진행 & easy setup status 확인
* json_path: 디바이스와 리소스에 대해 정의하고 있는 JSON 파일의 경로
* easysetup_complete: easysetup 완료 여부를 확인할 수 있는 boolean 변수의 주소
```C
int st_things_deinitialize(void);
```
SmartThings와의 연동이 끝날 때 detinitialize 프로세스 진행
### 주요 콜백 등록
#### Request Callback
```C
int st_things_register_request_cb(st_things_get_request_cb get_cb, st_things_set_request_cb set_cb);
```
SmartThings 클라우드로부터의 요청을 처리할 callback 함수 등록
* get_cb: Get 요청을 처리하는 콜백 함수
* set_cb: Set 요청을 처리하는 콜백 함수
#### Reset Callback
```C
int st_things_register_reset_cb(st_things_reset_confirm_cb confirm_cb, st_things_reset_result_cb result_cb);
```
디바이스 초기화 관련 함수 등록
* confirm_cb: 사용자의 확인을 처리하는 콜백 함수
* result_cb: 리셋 결과를 처리하는 콜백 함수
#### User Confirm Callback
```C
int st_things_register_user_confirm_cb(st_things_user_confirm_cb confirm_cb);
```
상호인증 방식으로 easy setup을 진행할 때 필요한 함수 등록
(PIN 값 대신 확인 버튼을 통해 easy setup 진행)
#### Things Status Change Callback
```C
int st_things_register_reset_cb(st_things_reset_confirm_cb confirm_cb, st_things_reset_result_cb result_cb);
```
SmartThings 클라우드와의 연동 과정에서 벌어지는 상태 변화를 확인하는 함수 등록
콜백 함수는 상태를 아래와 같은 Enum 값으로 받음
```C
typedef enum {
ST_THINGS_STATUS_INIT = 0, /**< 초기화 단계 */
ST_THINGS_STATUS_ES_STARTED, /**< 이지셋업 시작 */
ST_THINGS_STATUS_ES_DONE, /**< 이지셋업 완료 */
ST_THINGS_STATUS_ES_FAILED_ON_OWNERSHIP_TRANSFER, /**< 이지셋업 - 소유권 이전 실패 */
ST_THINGS_STATUS_CONNECTING_TO_AP, /**< 와이파이 접속 중 */
ST_THINGS_STATUS_CONNECTED_TO_AP, /**< 와이파이 접속 완료 */
ST_THINGS_STATUS_CONNECTING_TO_AP_FAILED, /**< 와이파이 접속 실패 */
ST_THINGS_STATUS_REGISTERING_TO_CLOUD, /**< 클라우드에 등록 중 */
ST_THINGS_STATUS_REGISTERED_TO_CLOUD, /**< 클라우드에 등록 완료, 이 시점부터 클라우드와 연결완료 */
ST_THINGS_STATUS_REGISTERING_FAILED_ON_SIGN_IN, /**< 클라우드에 로그인 실패 */
ST_THINGS_STATUS_REGISTERING_FAILED_ON_PUB_RES /**< 클라우드에 리소스 데이터 전달 실패 */
} st_things_status_e;
```
### 클라우드와의 연동
```C
int st_things_start(void);
```
```C
int st_things_stop(void);
```
### 초기화 ~ 자원정리 Flow
```C
bool easysetup_complete = false;
// 스마트싱즈와의 연동을 위해 내부적으로 관리하는 데이터들의 경로를 지정한다.
st_things_set_configuration_prefix_path("/ropath/XXX/res", "/rwpath/XXX/data"); /* Optional */
// 기구비된 JSON 설정파일로 초기화하고, 이지셋업 상태를 두번째 인자로 출력한다.
st_things_initialize("sample.json", &easysetup_complete);
// 이지셋업이 이전에 완료되지 않았다면, 이지셋업을 진행할지 아니면 종료할지를 결정한다.
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;
}
}
// 콜백 등록하기
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();
handle_main_loop();
// 클라우드와의 연동 종료하기
st_things_stop();
// 자원 정리하기
st_things_deinitialize();
```
## Handling Get/Set Requests
### Get Request Callback
```C
typedef bool (*st_things_get_request_cb)(st_things_get_request_message_s *req_msg, st_things_representation_s *resp_rep);
```
```C
typedef struct _st_things_get_request_message
{
char *resource_uri; /**< 요청 대상의 리소스 URI */
char *query; /**< 하나 이상의 질의인자. 예시 : key1=value1;key2=value2; */
char *property_key; /**< 하나 이상의 프로퍼티키. 예시 : key1;key2; */
/**
* @brief 질의문에서 지정된 키의 값을 확인하기
* @param[in] req_msg 요청 메시지
* @param[in] key 쿼리문 내의 키 이름
* @param[out] value 키에 대한 값
* @return 키가 존재하면 true, 존재하지 않으면 false를 리턴한다.
*/
bool (*get_query_value)(struct _st_things_get_request_message* req_msg, const char* key, char** value);
/**
* @brief 특정 프로퍼티키에 대한 요청이 있는지 여부 확인
* @param[in] req_msg 요청 메시지
* @param[in] key 질의문 내의 키 이름
* @return @c 키가 존재하면 true, 존재하지 않으면 false를 리턴한다.
*/
bool (*has_property_key)(struct _st_things_get_request_message* req_msg, const char* key);
} st_things_get_request_message_s;
```
### Set Request Callback
```C
typedef bool (*st_things_set_request_cb)(st_things_set_request_message_s *req_msg, st_things_representation_s *resp_rep);
```
```C
typedef struct _st_things_set_request_message
{
char*resource_uri; /**< 요청 대상의 리소스 URI */
char*query; /**< 하나 이상의 질의인자. 예시 : key1=value1;key2=value2; */
struct _st_things_representation* rep; /**< 요청 메시지에서 리소스 내용을 표현 */
/**
* @brief 질의문에서 지정된 키의 값을 확인하기
* @param[in] req_msg 요청 메시지
* @param[in] key 질의문 내의 키 이름
* @param[out] value 키에 대한 값
* @return 키가 존재하면 true, 존재하지 않으면 false를 리턴한다.
*/
bool (*get_query_value) (struct _st_things_set_request_message* req_msg, const char* key, char** value);
} st_things_set_request_message_s;
```
## Notifying Observers
```C
int st_things_notify_observers(const char *resource_uri);
```
특정 리소스(센서)에 변동사항이 생기면 클라우드에 알려줌
* resource_uri: 특정 리소스의 URI
***
# Devloper Workspace
[Developer Workspace 사이트](https://devworkspace.developer.samsung.com/smartthingsconsole/iotweb/site/index.html#/home)
## 새로운 Cloud-conncted Device 생성
1. Developer Workspace > Development > SmartThings Device > Cloud-connected > + Create 버튼 클릭

2. Device Information 입력

- **Device Name**: 디바이스 이름
- **Vendor ID**: 제조사가 발행하는 디바이스마다 임의로 정해주는 알바펫+숫자 조합의 ID이며, 각 제품은 고유한 VID를 갖게 됨
- **Description**: 디바이스 관련 설명
- **Device Type**: 디바이스 종류에 따라 SmartThings App 기본 UI가 정해짐 (본 실습에서는 MotionSensor 선택)
- **Device Capabilities**: 디바이스에서 사용하는 resource에 따라 Capabilities 선택 (본 실습에서는 Motion Sensor & Swith 선택)
- **Main State**: SmartThings App 초기 화면에 표시될 Main State 선택 (본 실습에서는 Motion Sensor : main 선택)
- **Main Action**: SmartThings App 초기 화면에서 컨트롤 가능한 Main Action 선택 (본 실습에서는 Swith : main 선택)
- **Device Plugin**: SmartThings App의 UI 변경이 필요하다면 Custom Device Plugin 사용
***Device Name / VID / Device Capabilities는 Tizen App의 정보와 같아야함으로 유의**
3. Self Publish 정보 입력

- **Display Name**: SmartThings App 이름
- **Device Onboarding ID**: SmartThings App에 연결 시 디바이스의 soft AP 이름에 사용될 임의의 숫자 3개 (본 실습에서는 000 입력)
***Device Onboarding ID는 Tizen App의 정보와 같아야함으로 유의**
4. Device Information 확인
- My cloud-connected devices 목록 > Device 이름 클릭

- **Device Name / VID / Device Capabilities / Device Onboarding ID는 Tizen App의 정보와 같아야함으로 유의**
- Status가 "Self-test"인지 확인
***
# Tizen SmartThings Template 앱 만들기
## Template Project 생성
1. Tizen Studio에서 File > New > Tizen Project > Template 선택

2. Iot-headless v4.0 선택 > Native Application 선택

3. Headless things app 선택 > Project Name & Package ID 설정

4. Basic Device 선택 > Device 관련 정보 입력

- Developer Workspace 내 Device 정보와 동일하게 입력
## IoT Cloud Certificate 생성
SmartThings App은 별도의 IoT Cloud용 인증서가 필요
1. Tools > Certificate Manager 선택 > IoT Cloud Service 탭 선택
2. 개인 정보 입력 / 디바이스 정보 입력
- MNID는 Developer Workspace의 MNID와 동일해야함으로 유의
- 본인의 MNID는 Worksapce의 계정 settings에서 확인 가능
3. 삼성 계정으로 로그인
- Developer Workspace에 등록된 Samsung 계정으로 로그인 (MNID 체크)
## SmartThings App - Device 연결
1. Tizen App 실행
- Project Explorer 내 프로젝트 우클릭 > Run As > Tizen Native App
2. SmartThing Mobile App에서 개발자 모드 설정
- 우측 상단 More(…) 버튼 클릭 > 설정 > 개발자모드 ON 선택
3. Device 추가
- 디바이스 탭 선택 > 디바이스 추가
- 본인의 디바이스 선택 (Easy Setup 자동 진행)
- App UI (Motion 표시창, Power 버튼) 확인
***
# Smart Motion Light SmartThings 앱 만들기
## 코드 준비
**1. Git Bash에서 rcc/smart-motion-light 코드 clone 받기**
```C
git clone https://review.tizen.org/gerrit/p/apps/native/st-things-light
```
**2. Tizen Studio에서 motion-light-smartthings 프로젝트 불러오기**
* File > Import >> Tizen > TIzen Project >> Root directory > Browse
* clone 받은 smart-motion-light 폴더 아래 smartthings-init 폴더 선택
* Project Name: motion-light-smartthings / Profile: iot-headless / Version: 4.0 선택 (이미 열려있는 프로젝트와 프로젝트명이 동일하면 안 열리니 주의)
## device_def.json 파일 변경
deviceName / manufacturerName / vendorId / setupId를 본인 고유 정보로 변경
(이전 스텝에서 생성한 template의 device_def.json 파일 사용 가능)
```json
{
"device": [
{
"specification": {
"device": {
"deviceType": "x.wwst.d.basic",
"deviceName": "***ENTER YOUR DEVICE NAME***",
"specVersion": "core.1.1.0",
"dataModelVersion": "res.1.1.0"
},
"platform": {
"manufacturerName": "***ENTER YOUR MNID***",
"manufacturerUrl": "http://www.samsung.com/sec/",
"manufacturingDate": "2017-11-29",
"modelNumber": "NWSP-01",
"platformVersion": "1.0",
"osVersion": "1.0",
"hardwareVersion": "1.0",
"firmwareVersion": "1.0",
"vendorId": "***ENTER YOUR VID***"
}
},
"resources": {
"single": [
{
"uri": "/capability/switch/main/0",
"types": [
"x.com.st.powerswitch"
],
"interfaces": [
"oic.if.a",
"oic.if.baseline"
],
"policy": 3
},
{
"uri": "/capability/motionSensor/main/0",
"types": [
"oic.r.sensor.motion"
],
"interfaces": [
"oic.if.s",
"oic.if.baseline"
],
"policy": 3
}
]
}
}
],
"resourceTypes": [
{
"type": "x.com.st.powerswitch",
"properties": [
{
"key": "power",
"type": 3,
"mandatory": true,
"rw": 3
}
]
},
{
"type": "oic.r.sensor.motion",
"properties": [
{
"key": "value",
"type": 0,
"mandatory": false,
"rw": 1
}
]
}
],
"configuration": {
"easySetup": {
"connectivity": {
"type": 1,
"softAP": {
"setupId": "***ENTER YOUR SETUP ID***",
"artik": false
}
},
"ownershipTransferMethod": 2
},
"wifi": {
"interfaces": 15,
"frequency": 1
},
"filePath": {
"svrdb": "artikserversecured.dat",
"provisioning": "provisioning.dat",
"certificate": "certificate.pem",
"privateKey": "privatekey.der"
}
}
}
```
## SmartThings API 사용 관련 Macro 값 확인
> src/controller.c
```C
#define JSON_NAME "device_def.json"
#define SENSOR_MOTION_URI "/capability/motionSensor/main/0"
#define SENSOR_MOTION_KEY "value"
#define SENSOR_LED_URI "/capability/switch/main/0"
#define SENSOR_LED_KEY "power"
#define SENSOR_LED_INIT "off"
```
## 디바이스 초기화 및 주요 콜백 등록
* 디바이스 설정 파일이 저장되는 경로를 지정
* SmartThings와의 연동을 위한 초기화 진행
* request / restet / user_confirm / status_change에 대한 콜백 함수 등록
> src/controller.c
```c
static int __things_init(void)
{
bool easysetup_complete = false;
char app_json_path[128] = {'', };
char *app_res_path = NULL;
char *app_data_path = NULL;
app_res_path = app_get_resource_path();
if (!app_res_path) {
_E("app_res_path is NULL!!");
return -1;
}
app_data_path = app_get_data_path();
if (!app_data_path) {
_E("app_data_path is NULL!!");
free(app_res_path);
return -1;
}
// TODO: Specify the read-only and read-write path
if (0 != st_things_set_configuration_prefix_path(app_res_path, app_data_path)) {
_E("st_things_set_configuration_prefix_path() failed!!");
free(app_res_path);
free(app_data_path);
return -1;
}
free(app_data_path);
snprintf(app_json_path, sizeof(app_json_path), "%s%s", app_res_path, JSON_NAME);
free(app_res_path);
// TODO: Specify the device configuration JSON file and change the status of easysetup_complete
if (0 != st_things_initialize(app_json_path, &easysetup_complete)) {
_E("st_things_initialize() failed!!");
return -1;
}
_D("easysetup_complete:[%d] ", easysetup_complete);
// TODO: Register callback for handling request get (handle_get_request) and request set (handle_set_request) messages
st_things_register_request_cb(handle_get_request, handle_set_request);
// TODO: Register callback for reset confirmation (handle_reset_request) and reset result(handle_reset_result) functions
st_things_register_reset_cb(handle_reset_request, handle_reset_result);
// TODO: Register callback for getting user confirmation for ownership transfer (handle_ownership_transfer_request)
st_things_register_user_confirm_cb(handle_ownership_transfer_request);
// TODO: Register callback for getting notified when ST Things state changes (handle_things_status_change)
st_things_register_things_status_change_cb(handle_things_status_change);
return 0;
}
```
## 센서 값들에 대한 Get Request 처리
### handle_get_request()
* Request 메시지의 resource_uri에 따라 get request 처리 함수 호출
> src/controller.c
```c
static bool handle_get_request(st_things_get_request_message_s* req_msg, st_things_representation_s* resp_rep)
{
bool ret = false;
_D("resource_uri [%s]", req_msg->resource_uri);
retv_if(!g_ad, false);
if (0 == strcmp(req_msg->resource_uri, SENSOR_MOTION_URI)) {
_D("query : %s, property: %s", req_msg->query, req_msg->property_key);
// TODO: Call handle get request function for motion sensor
ret = __handle_get_request_on_motion(req_msg, resp_rep);
} else if (0 == strcmp(req_msg->resource_uri, SENSOR_LED_URI)) {
_D("query : %s, property: %s", req_msg->query, req_msg->property_key);
// TODO: Call handle get request function for LED
ret = __handle_get_request_on_led(req_msg, resp_rep);
} else {
_E("not supported uri");
}
return ret;
}
```
### __handle_get_request_on_motion()
* Motion property 관련 데이터 값을 변경
> src/controller.c
```c
static bool __handle_get_request_on_motion (st_things_get_request_message_s* req_msg, st_things_representation_s* resp_rep)
{
if (req_msg->has_property_key(req_msg, SENSOR_MOTION_KEY)) {
bool value = false;
sensor_data_get_bool(g_ad->motion_data, &value);
// TODO: Update the response representation about the Sensor property which is sent to the client
resp_rep->set_bool_value(resp_rep, SENSOR_MOTION_KEY, value);
_D("Value : %d", value);
return true;
} else {
_E("not supported property");
return false;
}
}
```
### __handle_get_request_on_led()
* LED property 관련 데이터 값을 변경
> src/controller.c
```c
static bool __handle_get_request_on_led (st_things_get_request_message_s* req_msg, st_things_representation_s* resp_rep)
{
if (req_msg->has_property_key(req_msg, SENSOR_LED_KEY)) {
const char *str = NULL;
sensor_data_get_string(g_ad->led_data, &str);
if (!str) {
str = SENSOR_LED_INIT;
}
// TODO: Update the response representation about the LED property which is sent to the client
resp_rep->set_str_value(resp_rep, SENSOR_LED_KEY, str);
_D("Power : %s", str);
return true;
} else {
_E("not supported property");
return false;
}
}
```
## 센서 값들에 대한 Set Request 처리
### handle_set_request()
* Request 메시지의 resource_uri에 따라 set request 처리 함수 호출
> src/controller.c
```c
static bool handle_set_request(st_things_set_request_message_s* req_msg, st_things_representation_s* resp_rep)
{
bool ret = false;
_D("resource_uri [%s]", req_msg->resource_uri);
retv_if(!g_ad, false);
if (0 == strcmp(req_msg->resource_uri, SENSOR_LED_URI)) {
// TODO: Call handle set request function for LED
ret = __handle_set_request_on_led(req_msg, resp_rep);
} else {
_E("not supported uri");
}
return ret;
}
```
### __handle_set_request_on_led()
* LED property 관련 데이터 값 변경 및 LED의 상태 변경
> src/controller.c
```c
static bool __handle_set_request_on_led (st_things_set_request_message_s* req_msg, st_things_representation_s* resp_rep)
{
int ret = 0;
char *str = NULL;
if (req_msg->rep->get_str_value(req_msg->rep, SENSOR_LED_KEY, &str)) {
retv_if(!str, false);
_D("set [%s:%s] == %s", SENSOR_LED_URI, SENSOR_LED_KEY, str);
// TODO: Update the response representation about the LED property which is sent to the client
resp_rep->set_str_value(resp_rep, SENSOR_LED_KEY, str);
// Turn on LED light with __change_led_data()
ret = __change_led_data(g_ad, strdup(str));
retv_if(ret != 0, false);
} else {
_E("cannot get a string value");
return false;
}
free(str);
return true;
}
```
## Notification 설정
### __change_led_data() 함수 내 notify 설정
* LED 데이터 변경 시, 클라우드에 notify하도록 설정
```C
static int __change_led_data(void *data, char *state) {
int ret = 0;
app_data *ad = data;
retv_if(!ad, -1);
retv_if(!ad->led_data, -1);
sensor_data_set_string(g_ad->led_data, state, strlen(state));
if (0 == strcmp(state, LED_ON)) {
ret = resource_write_led(130, 1);
} else {
ret = resource_write_led(130, 0);
}
retv_if(ret != 0, -1);
// TODO: Notify observers of the LED resource
st_things_notify_observers(SENSOR_LED_URI);
return 0;
}
```
### __change_motion_sensor_data() 함수 내 notify 설정
* Motion sensor 데이터 변경 시, 클라우드에 notify하도록 설정
```C
static Eina_Bool __change_motion_sensor_data(void *data)
{
uint32_t value = 0;
/* Gets value from motion sensor */
int ret = resource_read_infrared_motion_sensor(46, &value);
if (ret != 0) _E("Cannot read sensor value");
sensor_data_set_bool(g_ad->motion_data, value);
_D("Detected motion value is: %d", value);
// TODO: Notify observers of the Sensor motion resource
st_things_notify_observers(SENSOR_MOTION_URI);
return ECORE_CALLBACK_RENEW;
}
```
## 앱 종료 시 resource 정리
> src/controller.c
```c
static void service_app_terminate(void *user_data)
{
app_data *ad = (app_data *)user_data;
// TODO: Delete ecore timer
if (ad->getter_motion)
ecore_timer_del(ad->getter_motion);
// TODO: Stop and deinitialize things
__things_stop();
__things_deinit();
// TODO: Turn off LED light with __set_led()
__set_led(ad, LED_OFF);
// TODO: Free sensor Motion & LED data
sensor_data_free(ad->motion_data);
sensor_data_free(ad->led_data);
// TODO: Close Motion and LED resources
resource_close_infrared_motion_sensor(46);
resource_close_led(130);
// TODO: Free app data
free(ad);
FN_END;
}
```
# 최종 확인
## 기존 App package 삭제
1. sdb shell 접속
* Device Manager > 폴더 표시창에서 우클릭 > Open shell 선택, 혹은
* 터미널에서 ./tizen-studio/tools/sdb shell
2. 기존에 설치되어 있는 앱 확인
```
pkgcmd -l -t tpk
```
3. motionlight & headlessthingsapp 패키지 삭제
```
pkgcmd -u -n org.tizen.motionlight
pkgcmd -u -n org.example.headlessthingsapp
```
## 기존 연결된 디바이스 삭제 (SmartThings 모바일 앱)
* 우측 상단 More(...) 버튼 클릭 > 편집 > 삭제(-) 버튼 클릭 > 삭제
## Motion Light Smartthings App 실행
1. Tizen App 실행
- Project Explorer 내 프로젝트 우클릭 > Run As > Tizen Native App
2. SmartThings App - Device 연결
- 디바이스 탭 선택 > 우측 상단 More(…) 버튼 클릭 > 기존의 디바이스 삭제
- 디바이스 추가 > 본인의 디바이스 선택 (Easy Setup 자동 진행)
3. SmartThings App - Device 간 상호작용 확인

Notice
Are you sure to delete this post?
Smart Motion Light SmartThings
1
2
|
Last modified on July 4, 2019
Craft info. | |
Maker |
![]() |
Status | In Progress |
Period | ~ |
About This Craft | |
Seoul IoT Presentation | |
Making Note