2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
4 * Contact: Jin Yoon <jinny.yoon@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 #include <service_app.h>
29 #include "resource_illuminance_sensor.h"
30 #include "resource_servo_motor.h"
35 #include "smartthings.h"
36 #include "smartthings_resource.h"
37 #include "smartthings_payload.h"
39 // Certificate file name in 'res' directory
40 #define CERT_FILE "certificate.pem"
41 // Private key file name in 'res' directory
42 #define PRIV_FILE "privatekey.der"
44 // SmartThings resource info for illuminance Sensor
45 #define SENSOR_URI_ILLUMINANCE "/capability/illuminanceMeasurement/main/0"
46 #define SENSOR_KEY_ILLUMINANCE "illuminance"
48 // SmartThings resource info for servo-motor
49 #define SENSOR_URI_DOOR "/capability/doorControl/main/0"
50 #define SENSOR_KEY_DOOR "doorState"
51 #define BLIND_UP "opening"
52 #define BLIND_DOWN "closing"
53 #define SENSOR_POWER_INITIALIZING BLIND_DOWN
54 #endif /* USE_ST_SDK */
56 // Peripheral info for Illuminance Sensor
57 #define I2C_BUS_NUMBER (1)
58 #define SENSOR_GATHER_INTERVAL (5.0f)
60 // Peripheral info for Servo-motor(HS-53)
61 // Duty Cycle : 0.54ms ~ 2.1ms
62 // Spec Duty Cycle : 0.553ms ~ 2.227ms(https://www.servocity.com/hitec-hs-53-servo)
63 #define SERVO_MOTOR_DUTY_CYCLE_COUNTER_CLOCKWISE 1.0
64 #define SERVO_MOTOR_DUTY_CYCLE_CLOCKWISE 2.0
66 typedef struct app_data_s {
67 uint32_t illuminance_value;
69 Ecore_Timer *getter_illuminance;
71 smartthings_h st_master_h;
72 smartthings_resource_h st_res_h;
73 smartthings_resource_connection_status_e st_res_conn_status;
74 #endif /* USE_ST_SDK */
77 static app_data *g_ad = NULL;
80 static const char *_resource_error_to_str(smartthings_resource_error_e error)
82 const char *err_str = NULL;
85 case SMARTTHINGS_RESOURCE_ERROR_NONE:
86 err_str = "SMARTTHINGS_RESOURCE_ERROR_NONE";
88 case SMARTTHINGS_RESOURCE_ERROR_INVALID_PARAMETER:
89 err_str = "SMARTTHINGS_RESOURCE_ERROR_INVALID_PARAMETER";
91 case SMARTTHINGS_RESOURCE_ERROR_OUT_OF_MEMORY:
92 err_str = "SMARTTHINGS_RESOURCE_ERROR_OUT_OF_MEMORY";
94 case SMARTTHINGS_RESOURCE_ERROR_PERMISSION_DENIED:
95 err_str = "SMARTTHINGS_RESOURCE_ERROR_PERMISSION_DENIED";
97 case SMARTTHINGS_RESOURCE_ERROR_NO_DATA:
98 err_str = "SMARTTHINGS_RESOURCE_ERROR_NO_DATA";
100 case SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED:
101 err_str = "SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED";
103 case SMARTTHINGS_RESOURCE_ERROR_OPERATION_FAILED:
104 err_str = "SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED";
106 case SMARTTHINGS_RESOURCE_ERROR_SERVICE_UNAVAILABLE:
107 err_str = "SMARTTHINGS_RESOURCE_ERROR_SERVICE_UNAVAILABLE";
110 err_str = "Unknown error";
118 static Eina_Bool _get_illuminance(void *data)
123 retv_if(!ad, ECORE_CALLBACK_CANCEL);
125 ret = resource_read_illuminance_sensor(I2C_BUS_NUMBER, &ad->illuminance_value);
126 retv_if(ret != 0, ECORE_CALLBACK_CANCEL);
128 _D("Illuminance value : %u", ad->illuminance_value);
131 int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
132 smartthings_payload_h resp_payload = NULL;
134 error = smartthings_payload_create(&resp_payload);
135 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE || !resp_payload) {
136 _E("smartthings_payload_create() failed, [%s]",
137 _resource_error_to_str(error));
138 return ECORE_CALLBACK_CANCEL;
141 error = smartthings_payload_set_int(resp_payload, SENSOR_KEY_ILLUMINANCE, (int)ad->illuminance_value);
142 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
143 _E("smartthings_payload_set_int() failed, [%s]",
144 _resource_error_to_str(error));
146 error = smartthings_resource_notify(ad->st_res_h, SENSOR_URI_ILLUMINANCE, resp_payload);
147 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
148 _E("smartthings_resource_notify() failed, [%s]",
149 _resource_error_to_str(error));
151 if (smartthings_payload_destroy(resp_payload))
152 _E("smartthings_payload_destroy() failed");
155 return ECORE_CALLBACK_RENEW;
158 static void _stop_gathering(void *data)
164 if (ad->getter_illuminance) {
165 ecore_timer_del(ad->getter_illuminance);
166 ad->getter_illuminance = NULL;
170 static void _start_gathering(void *data)
178 ad->getter_illuminance = ecore_timer_add(SENSOR_GATHER_INTERVAL, _get_illuminance, ad);
179 if (!ad->getter_illuminance)
180 _E("Failed to add getter_illuminance");
184 /* SmartThings resource functions */
185 static bool _handle_get_request_on_resource_capability_illuminancemeasurement_main_0(smartthings_payload_h resp_payload, void *user_data)
187 app_data *ad = user_data;
189 int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
191 retv_if(!resp_payload, false);
194 ret = resource_read_illuminance_sensor(I2C_BUS_NUMBER, &ad->illuminance_value);
195 retv_if(ret != 0, false);
197 _D("Received a GET request : Illuminance is %u", ad->illuminance_value);
199 error = smartthings_payload_set_int(resp_payload, SENSOR_KEY_ILLUMINANCE, (int)ad->illuminance_value);
200 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
201 _E("smartthings_payload_set_int() failed, [%s]",
202 _resource_error_to_str(error));
209 static bool _handle_get_request_on_resource_capability_doorcontrol_main_0(smartthings_payload_h resp_payload, void *user_data)
211 app_data *ad = user_data;
212 int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
214 retv_if(!resp_payload, false);
217 _D("Received a GET request");
219 error = smartthings_payload_set_string(resp_payload, SENSOR_KEY_DOOR, ad->motor_string);
220 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
221 _E("smartthings_payload_set_string() failed, [%s]",
222 _resource_error_to_str(error));
229 static int _set_servo_motor(int on)
231 double duty_cycle = 0;
235 duty_cycle = SERVO_MOTOR_DUTY_CYCLE_CLOCKWISE;
237 duty_cycle = SERVO_MOTOR_DUTY_CYCLE_COUNTER_CLOCKWISE;
239 ret = resource_set_servo_motor_value(duty_cycle);
240 retv_if(ret != 0, -1);
245 static bool _handle_set_request_on_resource_capability_doorcontrol_main_0(smartthings_payload_h payload, smartthings_payload_h resp_payload, void *user_data)
247 app_data *ad = user_data;
250 int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
252 retv_if(!payload, false);
253 retv_if(!resp_payload, false);
256 _D("Received a SET request");
258 error = smartthings_payload_get_string(payload, SENSOR_KEY_DOOR, &str);
259 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
260 _E("smartthings_payload_get_string() failed, [%s]",
261 _resource_error_to_str(error));
264 if (!str || strncmp(str, BLIND_DOWN, strlen(BLIND_DOWN))) {
265 ad->motor_string = BLIND_UP;
266 ret = _set_servo_motor(1);
268 ad->motor_string = BLIND_DOWN;
269 ret = _set_servo_motor(0);
273 error = smartthings_payload_set_string(resp_payload, SENSOR_KEY_DOOR, ad->motor_string);
274 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
275 _E("smartthings_payload_set_string() failed, [%s]",
276 _resource_error_to_str(error));
284 static void _request_cb(smartthings_resource_h handle, int req_id,
285 const char *uri, smartthings_resource_req_type_e req_type,
286 smartthings_payload_h payload, void *user_data)
288 smartthings_payload_h resp_payload = NULL;
290 int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
292 _D("request on %s, type[%d], id[%d]", uri, req_type, req_id);
294 error = smartthings_payload_create(&resp_payload);
295 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE || !resp_payload) {
296 _E("smartthings_payload_create() failed, [%s]",
297 _resource_error_to_str(error));
301 if (req_type == SMARTTHINGS_RESOURCE_REQUEST_GET) {
302 if (!strncmp(uri, SENSOR_URI_ILLUMINANCE, strlen(SENSOR_URI_ILLUMINANCE)))
303 result = _handle_get_request_on_resource_capability_illuminancemeasurement_main_0(resp_payload, user_data);
304 else if (!strncmp(uri, SENSOR_URI_DOOR, strlen(SENSOR_URI_DOOR)))
305 result = _handle_get_request_on_resource_capability_doorcontrol_main_0(resp_payload, user_data);
307 _E("No matching Resource uri to get");
308 } else if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
309 if (!strncmp(uri, SENSOR_URI_DOOR, strlen(SENSOR_URI_DOOR)))
310 result = _handle_set_request_on_resource_capability_doorcontrol_main_0(payload, resp_payload, user_data);
312 _E("No matching Resource uri to set");
314 _E("Invalid request type - %d", req_type);
315 smartthings_payload_destroy(resp_payload);
319 error = smartthings_resource_send_response(handle, req_id, uri, resp_payload, result);
320 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
321 smartthings_payload_destroy(resp_payload);
322 _E("smartthings_payload_destroy() failed, [%s]",
323 _resource_error_to_str(error));
327 if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
328 error = smartthings_resource_notify(handle, uri, resp_payload);
329 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
330 _E("smartthings_resource_notify() failed, [%s]",
331 _resource_error_to_str(error));
334 if (smartthings_payload_destroy(resp_payload))
335 _E("smartthings_payload_destroy failed");
338 static void _resource_connection_status_cb(smartthings_resource_h handle,
339 smartthings_resource_connection_status_e status, void *user_data)
341 app_data *ad = user_data;
342 int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
346 ad->st_res_conn_status = status;
347 _D("status=[%d]", status);
349 if (status == SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED) {
350 error = smartthings_resource_set_request_cb(handle, _request_cb, ad);
351 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
352 _E("smartthings_resource_set_request_cb() is failed");
356 _E("connection failed");
360 static int _init_resource(app_data *ad)
362 smartthings_resource_h st_res_h = NULL;
368 _I("Already initialized!");
372 error = smartthings_resource_initialize(&st_res_h,
373 _resource_connection_status_cb, ad);
375 _E("smartthings_resource_initialize() is failed, [%s]",
376 _resource_error_to_str(error));
380 ad->st_res_h = st_res_h;
381 ad->st_res_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
386 static int _fini_resource(app_data *ad)
393 smartthings_resource_unset_request_cb(ad->st_res_h);
394 smartthings_resource_deinitialize(ad->st_res_h);
397 ad->st_res_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
402 /* smartthings master functions */
403 static const char *_master_error_to_str(smartthings_error_e error)
405 const char *err_str = NULL;
408 case SMARTTHINGS_ERROR_NONE:
409 err_str = "SMARTTHINGS_ERROR_NONE";
411 case SMARTTHINGS_ERROR_INVALID_PARAMETER:
412 err_str = "SMARTTHINGS_ERROR_INVALID_PARAMETER";
414 case SMARTTHINGS_ERROR_OUT_OF_MEMORY:
415 err_str = "SMARTTHINGS_ERROR_OUT_OF_MEMORY";
417 case SMARTTHINGS_ERROR_PERMISSION_DENIED:
418 err_str = "SMARTTHINGS_ERROR_PERMISSION_DENIED";
420 case SMARTTHINGS_ERROR_NO_DATA:
421 err_str = "SMARTTHINGS_ERROR_NO_DATA";
423 case SMARTTHINGS_ERROR_NOT_SUPPORTED:
424 err_str = "SMARTTHINGS_ERROR_NOT_SUPPORTED";
426 case SMARTTHINGS_ERROR_OPERATION_FAILED:
427 err_str = "SMARTTHINGS_ERROR_OPERATION_FAILED";
429 case SMARTTHINGS_ERROR_SERVICE_UNAVAILABLE:
430 err_str = "SMARTTHINGS_ERROR_SERVICE_UNAVAILABLE";
433 err_str = "Unknown error";
440 static void _user_confirm_cb(smartthings_h handle, void *user_data)
442 if (smartthings_send_user_confirm(handle, true) != 0)
443 _E("smartthings_send_user_confirm() is failed");
446 static void _reset_confirm_cb(smartthings_h handle, void *user_data)
448 if (smartthings_send_reset_confirm(handle, true) != 0)
449 _E("smartthings_send_reset_confirm() is failed");
452 static void _reset_result_cb(smartthings_h handle, bool result, void *user_data)
454 _I("reset result = [%d]", result);
457 static void _thing_status_cb(smartthings_h handle, smartthings_status_e status, void *user_data)
459 _D("status: [%d]", status);
462 static void _things_connection_status_cb(smartthings_h handle, smartthings_connection_status_e status,
465 _D("status = [%d]", status);
467 if (status == SMARTTHINGS_CONNECTION_STATUS_CONNECTED) {
469 bool is_es_completed = false;
470 const char* dev_name = "co2-app";
471 int wifi_mode = SMARTTHINGS_WIFI_MODE_11B
472 | SMARTTHINGS_WIFI_MODE_11G
473 | SMARTTHINGS_WIFI_MODE_11N;
475 int wifi_freq = SMARTTHINGS_WIFI_FREQ_24G
476 | SMARTTHINGS_WIFI_FREQ_5G;
478 err = smartthings_set_device_property(
479 handle, dev_name, wifi_mode, wifi_freq);
481 _E("smartthings_set_device_property() is failed, [%s]",
482 _master_error_to_str(err));
486 err = smartthings_set_certificate_file(handle, CERT_FILE, PRIV_FILE);
488 _E("smartthings_set_certificate_file() is failed, [%s]",
489 _master_error_to_str(err));
493 err = smartthings_set_user_confirm_cb(handle, _user_confirm_cb, NULL);
495 _E("smartthings_set_user_confirm_cb() is failed, [%s]",
496 _master_error_to_str(err));
500 err = smartthings_set_reset_confirm_cb(handle, _reset_confirm_cb, NULL);
502 _E("smartthings_set_reset_confirm_cb() is failed, [%s]",
503 _master_error_to_str(err));
507 err = smartthings_set_reset_result_cb(handle, _reset_result_cb, NULL);
509 _E("smartthings_set_reset_result_cb() is failed, [%s]",
510 _master_error_to_str(err));
514 err = smartthings_set_status_changed_cb(handle, _thing_status_cb, NULL);
516 _E("smartthings_set_status_changed_callback() is failed, [%s]",
517 _master_error_to_str(err));
521 err = smartthings_start(handle);
523 _E("smartthings_start() is failed, [%s]",
524 _master_error_to_str(err));
528 err = smartthings_get_easysetup_status(handle, &is_es_completed);
530 _E("smartthings_get_easysetup_status() is failed, [%s]",
531 _master_error_to_str(err));
535 if (is_es_completed == true) {
536 _I("Easysetup is already done");
540 err = smartthings_start_easysetup(handle);
542 _E("smartthings_start_easysetup() is failed, [%s]",
543 _master_error_to_str(err));
544 smartthings_stop(handle);
548 _E("connection failed");
552 static int _init_master(app_data *ad)
554 int error = SMARTTHINGS_ERROR_NONE;
555 smartthings_h st_handle = NULL;
559 if (ad->st_master_h) {
560 _I("Already initialized!");
564 error = smartthings_initialize(&st_handle, _things_connection_status_cb, NULL);
566 _E("smartthings_initialize() is failed, [%s]",
567 _master_error_to_str(error));
571 ad->st_master_h = st_handle;
576 int _fini_master(app_data *ad)
580 if (!ad->st_master_h) {
581 _I("handle is already NULL");
585 smartthings_unset_user_confirm_cb(ad->st_master_h);
586 smartthings_unset_reset_confirm_cb(ad->st_master_h);
587 smartthings_unset_reset_result_cb(ad->st_master_h);
588 smartthings_unset_status_changed_cb(ad->st_master_h);
590 smartthings_stop_easysetup(ad->st_master_h);
591 smartthings_stop(ad->st_master_h);
593 if (smartthings_deinitialize(ad->st_master_h) != 0) {
594 _E("smartthings_deinitialize() is failed");
597 ad->st_master_h = NULL;
603 static bool service_app_create(void *user_data)
606 app_data *ad = user_data;
608 ad->illuminance_value = 100;
609 ad->motor_string = BLIND_UP;
611 if (_init_master(ad))
614 if (_init_resource(ad)) {
623 static void service_app_terminate(void *user_data)
625 app_data *ad = user_data;
630 resource_close_servo_motor();
631 resource_close_illuminance_sensor();
641 static void service_app_control(app_control_h app_control, void *user_data)
643 app_data *ad = user_data;
644 _start_gathering(ad);
647 int main(int argc, char *argv[])
650 service_app_lifecycle_callback_s event_callback;
652 ad = calloc(1, sizeof(app_data));
657 event_callback.create = service_app_create;
658 event_callback.terminate = service_app_terminate;
659 event_callback.app_control = service_app_control;
661 return service_app_main(argc, argv, &event_callback, ad);