Change all the SmartThings APIs for Tizen 5.0
[apps/native/st-things-blind.git] / src / st-things-blind.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Contact: Jin Yoon <jinny.yoon@samsung.com>
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19
20 #include <tizen.h>
21 #include <service_app.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <Ecore.h>
27
28 #include "log.h"
29 #include "resource_illuminance_sensor.h"
30 #include "resource_servo_motor.h"
31
32 #define USE_ST_SDK
33
34 #ifdef USE_ST_SDK
35 #include "smartthings.h"
36 #include "smartthings_resource.h"
37 #include "smartthings_payload.h"
38
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"
43
44 // SmartThings resource info for illuminance Sensor
45 #define SENSOR_URI_ILLUMINANCE "/capability/illuminanceMeasurement/main/0"
46 #define SENSOR_KEY_ILLUMINANCE "illuminance"
47
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 */
55
56 // Peripheral info for Illuminance Sensor
57 #define I2C_BUS_NUMBER (1)
58 #define SENSOR_GATHER_INTERVAL (5.0f)
59
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
65
66 typedef struct app_data_s {
67         uint32_t illuminance_value;
68         char *motor_string;
69         Ecore_Timer *getter_illuminance;
70 #ifdef USE_ST_SDK
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 */
75 } app_data;
76
77 static app_data *g_ad = NULL;
78
79 #ifdef USE_ST_SDK
80 static const char *_resource_error_to_str(smartthings_resource_error_e error)
81 {
82         const char *err_str = NULL;
83
84         switch (error) {
85         case SMARTTHINGS_RESOURCE_ERROR_NONE:
86                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NONE";
87                 break;
88         case SMARTTHINGS_RESOURCE_ERROR_INVALID_PARAMETER:
89                 err_str = "SMARTTHINGS_RESOURCE_ERROR_INVALID_PARAMETER";
90                 break;
91         case SMARTTHINGS_RESOURCE_ERROR_OUT_OF_MEMORY:
92                 err_str = "SMARTTHINGS_RESOURCE_ERROR_OUT_OF_MEMORY";
93                 break;
94         case SMARTTHINGS_RESOURCE_ERROR_PERMISSION_DENIED:
95                 err_str = "SMARTTHINGS_RESOURCE_ERROR_PERMISSION_DENIED";
96                 break;
97         case SMARTTHINGS_RESOURCE_ERROR_NO_DATA:
98                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NO_DATA";
99                 break;
100         case SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED:
101                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED";
102                 break;
103         case SMARTTHINGS_RESOURCE_ERROR_OPERATION_FAILED:
104                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED";
105                 break;
106         case SMARTTHINGS_RESOURCE_ERROR_SERVICE_UNAVAILABLE:
107                 err_str = "SMARTTHINGS_RESOURCE_ERROR_SERVICE_UNAVAILABLE";
108                 break;
109         default:
110                 err_str = "Unknown error";
111                 break;
112         }
113
114         return err_str;
115 }
116 #endif
117
118 static Eina_Bool _get_illuminance(void *data)
119 {
120         int ret = 0;
121         app_data *ad = data;
122
123         retv_if(!ad, ECORE_CALLBACK_CANCEL);
124
125         ret = resource_read_illuminance_sensor(I2C_BUS_NUMBER, &ad->illuminance_value);
126         retv_if(ret != 0, ECORE_CALLBACK_CANCEL);
127
128         _D("Illuminance value : %u", ad->illuminance_value);
129
130 #ifdef USE_ST_SDK
131         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
132         smartthings_payload_h resp_payload = NULL;
133
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;
139         }
140
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));
145
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));
150
151         if (smartthings_payload_destroy(resp_payload))
152                 _E("smartthings_payload_destroy() failed");
153 #endif
154
155         return ECORE_CALLBACK_RENEW;
156 }
157
158 static void _stop_gathering(void *data)
159 {
160         app_data *ad = data;
161
162         ret_if(!ad);
163
164         if (ad->getter_illuminance) {
165                 ecore_timer_del(ad->getter_illuminance);
166                 ad->getter_illuminance = NULL;
167         }
168 }
169
170 static void _start_gathering(void *data)
171 {
172         app_data *ad = data;
173
174         ret_if(!ad);
175
176         _stop_gathering(ad);
177
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");
181 }
182
183 #ifdef USE_ST_SDK
184 /* SmartThings resource functions */
185 static bool _handle_get_request_on_resource_capability_illuminancemeasurement_main_0(smartthings_payload_h resp_payload, void *user_data)
186 {
187         app_data *ad = user_data;
188         int ret = 0;
189         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
190
191         retv_if(!resp_payload, false);
192         retv_if(!ad, false);
193
194         ret = resource_read_illuminance_sensor(I2C_BUS_NUMBER, &ad->illuminance_value);
195         retv_if(ret != 0, false);
196
197     _D("Received a GET request : Illuminance is %u", ad->illuminance_value);
198
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));
203                 return false;
204         }
205
206     return true;
207 }
208
209 static bool _handle_get_request_on_resource_capability_doorcontrol_main_0(smartthings_payload_h resp_payload, void *user_data)
210 {
211         app_data *ad = user_data;
212         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
213
214         retv_if(!resp_payload, false);
215         retv_if(!ad, false);
216
217         _D("Received a GET request");
218
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));
223                 return false;
224         }
225
226         return true;
227 }
228
229 static int _set_servo_motor(int on)
230 {
231         double duty_cycle = 0;
232         int ret = 0;
233
234         if (on)
235                 duty_cycle = SERVO_MOTOR_DUTY_CYCLE_CLOCKWISE;
236         else
237                 duty_cycle = SERVO_MOTOR_DUTY_CYCLE_COUNTER_CLOCKWISE;
238
239         ret = resource_set_servo_motor_value(duty_cycle);
240         retv_if(ret != 0, -1);
241
242         return 0;
243 }
244
245 static bool _handle_set_request_on_resource_capability_doorcontrol_main_0(smartthings_payload_h payload, smartthings_payload_h resp_payload, void *user_data)
246 {
247         app_data *ad = user_data;
248         char *str = NULL;
249         int ret = 0;
250         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
251
252         retv_if(!payload, false);
253         retv_if(!resp_payload, false);
254         retv_if(!ad, false);
255
256     _D("Received a SET request");
257
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));
262         }
263
264     if (!str || strncmp(str, BLIND_DOWN, strlen(BLIND_DOWN))) {
265                 ad->motor_string = BLIND_UP;
266                 ret = _set_servo_motor(1);
267     } else {
268                 ad->motor_string = BLIND_DOWN;
269                 ret = _set_servo_motor(0);
270         }
271         free(str);
272
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));
277                 return false;
278         }
279
280     return true;
281 }
282
283
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)
287 {
288         smartthings_payload_h resp_payload = NULL;
289         bool result = false;
290         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
291
292         _D("request on %s, type[%d], id[%d]", uri, req_type, req_id);
293
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));
298                 return;
299         }
300
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);
306                 else
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);
311                 else
312                         _E("No matching Resource uri to set");
313         } else {
314                 _E("Invalid request type - %d", req_type);
315                 smartthings_payload_destroy(resp_payload);
316                 return;
317         }
318
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));
324                 return;
325         }
326
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));
332         }
333
334         if (smartthings_payload_destroy(resp_payload))
335                 _E("smartthings_payload_destroy failed");
336 }
337
338 static void _resource_connection_status_cb(smartthings_resource_h handle,
339         smartthings_resource_connection_status_e status, void *user_data)
340 {
341         app_data *ad = user_data;
342         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
343
344         ret_if(!ad);
345
346         ad->st_res_conn_status = status;
347         _D("status=[%d]", status);
348
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");
353                         return;
354                 }
355         } else {
356                 _E("connection failed");
357         }
358 }
359
360 static int _init_resource(app_data *ad)
361 {
362         smartthings_resource_h st_res_h = NULL;
363         int error = 0;
364
365         retv_if(!ad, -1);
366
367         if (ad->st_res_h) {
368                 _I("Already initialized!");
369                 return 0;
370         }
371
372         error = smartthings_resource_initialize(&st_res_h,
373                                 _resource_connection_status_cb, ad);
374         if (error) {
375                 _E("smartthings_resource_initialize() is failed, [%s]",
376                         _resource_error_to_str(error));
377                 return -1;
378         }
379
380         ad->st_res_h = st_res_h;
381         ad->st_res_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
382
383         return 0;
384 }
385
386 static int _fini_resource(app_data *ad)
387 {
388         retv_if(!ad, -1);
389
390         if (!ad->st_res_h)
391                 return 0;
392
393         smartthings_resource_unset_request_cb(ad->st_res_h);
394         smartthings_resource_deinitialize(ad->st_res_h);
395
396         ad->st_res_h = NULL;
397         ad->st_res_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
398
399         return 0;
400 }
401
402 /* smartthings master functions */
403 static const char *_master_error_to_str(smartthings_error_e error)
404 {
405         const char *err_str = NULL;
406
407         switch (error) {
408         case SMARTTHINGS_ERROR_NONE:
409                 err_str = "SMARTTHINGS_ERROR_NONE";
410                 break;
411         case SMARTTHINGS_ERROR_INVALID_PARAMETER:
412                 err_str = "SMARTTHINGS_ERROR_INVALID_PARAMETER";
413                 break;
414         case SMARTTHINGS_ERROR_OUT_OF_MEMORY:
415                 err_str = "SMARTTHINGS_ERROR_OUT_OF_MEMORY";
416                 break;
417         case SMARTTHINGS_ERROR_PERMISSION_DENIED:
418                 err_str = "SMARTTHINGS_ERROR_PERMISSION_DENIED";
419                 break;
420         case SMARTTHINGS_ERROR_NO_DATA:
421                 err_str = "SMARTTHINGS_ERROR_NO_DATA";
422                 break;
423         case SMARTTHINGS_ERROR_NOT_SUPPORTED:
424                 err_str = "SMARTTHINGS_ERROR_NOT_SUPPORTED";
425                 break;
426         case SMARTTHINGS_ERROR_OPERATION_FAILED:
427                 err_str = "SMARTTHINGS_ERROR_OPERATION_FAILED";
428                 break;
429         case SMARTTHINGS_ERROR_SERVICE_UNAVAILABLE:
430                 err_str = "SMARTTHINGS_ERROR_SERVICE_UNAVAILABLE";
431                 break;
432         default:
433                 err_str = "Unknown error";
434                 break;
435         }
436
437         return err_str;
438 }
439
440 static void _user_confirm_cb(smartthings_h handle, void *user_data)
441 {
442         if (smartthings_send_user_confirm(handle, true) != 0)
443                 _E("smartthings_send_user_confirm() is failed");
444 }
445
446 static void _reset_confirm_cb(smartthings_h handle, void *user_data)
447 {
448         if (smartthings_send_reset_confirm(handle, true) != 0)
449                 _E("smartthings_send_reset_confirm() is failed");
450 }
451
452 static void _reset_result_cb(smartthings_h handle, bool result, void *user_data)
453 {
454         _I("reset result = [%d]", result);
455 }
456
457 static void _thing_status_cb(smartthings_h handle, smartthings_status_e status, void *user_data)
458 {
459         _D("status: [%d]", status);
460 }
461
462 static void _things_connection_status_cb(smartthings_h handle, smartthings_connection_status_e status,
463         void *user_data)
464 {
465         _D("status = [%d]", status);
466
467         if (status == SMARTTHINGS_CONNECTION_STATUS_CONNECTED) {
468                 int err = 0;
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;
474
475                 int wifi_freq = SMARTTHINGS_WIFI_FREQ_24G
476                         | SMARTTHINGS_WIFI_FREQ_5G;
477
478                 err = smartthings_set_device_property(
479                                         handle, dev_name, wifi_mode, wifi_freq);
480                 if (err) {
481                         _E("smartthings_set_device_property() is failed, [%s]",
482                                 _master_error_to_str(err));
483                         return;
484                 }
485
486                 err = smartthings_set_certificate_file(handle, CERT_FILE, PRIV_FILE);
487                 if (err) {
488                         _E("smartthings_set_certificate_file() is failed, [%s]",
489                                 _master_error_to_str(err));
490                         return;
491                 }
492
493                 err = smartthings_set_user_confirm_cb(handle, _user_confirm_cb, NULL);
494                 if (err) {
495                         _E("smartthings_set_user_confirm_cb() is failed, [%s]",
496                                 _master_error_to_str(err));
497                         return;
498                 }
499
500                 err = smartthings_set_reset_confirm_cb(handle, _reset_confirm_cb, NULL);
501                 if (err) {
502                         _E("smartthings_set_reset_confirm_cb() is failed, [%s]",
503                                 _master_error_to_str(err));
504                         return;
505                 }
506
507                 err = smartthings_set_reset_result_cb(handle, _reset_result_cb, NULL);
508                 if (err) {
509                         _E("smartthings_set_reset_result_cb() is failed, [%s]",
510                                 _master_error_to_str(err));
511                         return;
512                 }
513
514                 err = smartthings_set_status_changed_cb(handle, _thing_status_cb, NULL);
515                 if (err) {
516                         _E("smartthings_set_status_changed_callback() is failed, [%s]",
517                                 _master_error_to_str(err));
518                         return;
519                 }
520
521                 err = smartthings_start(handle);
522                 if (err) {
523                         _E("smartthings_start() is failed, [%s]",
524                                 _master_error_to_str(err));
525                         return;
526                 }
527
528                 err = smartthings_get_easysetup_status(handle, &is_es_completed);
529                 if (err) {
530                         _E("smartthings_get_easysetup_status() is failed, [%s]",
531                                 _master_error_to_str(err));
532                         return;
533                 }
534
535                 if (is_es_completed == true) {
536                         _I("Easysetup is already done");
537                         return;
538                 }
539
540                 err = smartthings_start_easysetup(handle);
541                 if (err) {
542                         _E("smartthings_start_easysetup() is failed, [%s]",
543                                 _master_error_to_str(err));
544                         smartthings_stop(handle);
545                         return;
546                 }
547         } else {
548                         _E("connection failed");
549         }
550 }
551
552 static int _init_master(app_data *ad)
553 {
554         int error = SMARTTHINGS_ERROR_NONE;
555         smartthings_h st_handle = NULL;
556
557         retv_if(!ad, -1);
558
559         if (ad->st_master_h) {
560                 _I("Already initialized!");
561                 return 0;
562         }
563
564         error = smartthings_initialize(&st_handle, _things_connection_status_cb, NULL);
565         if (error) {
566                 _E("smartthings_initialize() is failed, [%s]",
567                         _master_error_to_str(error));
568                 return -1;
569         }
570
571         ad->st_master_h = st_handle;
572
573         return 0;
574 }
575
576 int _fini_master(app_data *ad)
577 {
578         retv_if(!ad, -1);
579
580         if (!ad->st_master_h) {
581                 _I("handle is already NULL");
582                 return 0;
583         }
584
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);
589
590         smartthings_stop_easysetup(ad->st_master_h);
591         smartthings_stop(ad->st_master_h);
592
593         if (smartthings_deinitialize(ad->st_master_h) != 0)  {
594                 _E("smartthings_deinitialize() is failed");
595                 return -1;
596         }
597         ad->st_master_h = NULL;
598
599         return 0;
600 }
601 #endif
602
603 static bool service_app_create(void *user_data)
604 {
605 #ifdef USE_ST_SDK
606         app_data *ad = user_data;
607
608         ad->illuminance_value = 100;
609         ad->motor_string = BLIND_UP;
610
611         if (_init_master(ad))
612                 return false;
613
614         if (_init_resource(ad)) {
615                 _fini_master(ad);
616                 return false;
617         }
618 #endif
619
620         return true;
621 }
622
623 static void service_app_terminate(void *user_data)
624 {
625         app_data *ad = user_data;
626         if (!ad)
627                 return;
628
629         _stop_gathering(ad);
630         resource_close_servo_motor();
631         resource_close_illuminance_sensor();
632
633 #ifdef USE_ST_SDK
634         _fini_resource(ad);
635         _fini_master(ad);
636 #endif
637
638         free(ad);
639 }
640
641 static void service_app_control(app_control_h app_control, void *user_data)
642 {
643         app_data *ad = user_data;
644         _start_gathering(ad);
645 }
646
647 int main(int argc, char *argv[])
648 {
649         app_data *ad = NULL;
650         service_app_lifecycle_callback_s event_callback;
651
652         ad = calloc(1, sizeof(app_data));
653         retv_if(!ad, -1);
654
655         g_ad = ad;
656
657         event_callback.create = service_app_create;
658         event_callback.terminate = service_app_terminate;
659         event_callback.app_control = service_app_control;
660
661         return service_app_main(argc, argv, &event_callback, ad);
662 }