update for iot-5.0
[apps/native/st-things-co2-meter.git] / src / co2.c
1 /* ****************************************************************
2  *
3  * Copyright 2017 Samsung Electronics All Rights Reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  ******************************************************************/
18
19 #include <tizen.h>
20 #include <service_app.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <glib.h>
24
25 #include "log.h"
26 #include "sensor-data.h"
27 #include "co2-sensor.h"
28
29 #define SENSOR_CH_CO2 (0)
30 #define SENSOR_GATHER_INTERVAL (50) //50ms
31 #define SENSOR_GATHER_COUNT (60)
32
33 //#define USE_ST_SDK
34
35 #ifdef USE_ST_SDK
36
37 #include "smartthings.h"
38 #include "smartthings_resource.h"
39 #include "smartthings_payload.h"
40
41 /*  You have to FIX IT !!!  */
42 #define CERT_FILE "certificate.pem" // cert file name in 'res' directory
43 #define PRIV_FILE "privatekey.der" // private key file name in 'res' directory
44
45
46 #define SENSOR_URI_CO2 "/capability/airQualitySensor/main/0"
47 #define SENSOR_KEY_CO2 "airQuality"
48
49 #endif /* USE_ST_SDK */
50
51 typedef struct app_data_s {
52         guint getter_co2;
53         sensor_data *co2_data;
54 #ifdef USE_ST_SDK
55         smartthings_h st_master_h;
56         smartthings_resource_h st_res_h;
57         smartthings_resource_connection_status_e st_res_conn_status;
58 #endif /* USE_ST_SDK */
59 } app_data;
60
61 static app_data *g_ad = NULL;
62
63 #ifdef USE_ST_SDK
64
65 /* smartthings resource functions */
66 static const char *
67 __resource_error_to_str(smartthings_resource_error_e error)
68 {
69         const char *err_str = NULL;
70
71         switch (error) {
72         case SMARTTHINGS_RESOURCE_ERROR_NONE:
73                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NONE";
74                 break;
75         case SMARTTHINGS_RESOURCE_ERROR_INVALID_PARAMETER:
76                 err_str = "SMARTTHINGS_RESOURCE_ERROR_INVALID_PARAMETER";
77                 break;
78         case SMARTTHINGS_RESOURCE_ERROR_OUT_OF_MEMORY:
79                 err_str = "SMARTTHINGS_RESOURCE_ERROR_OUT_OF_MEMORY";
80                 break;
81         case SMARTTHINGS_RESOURCE_ERROR_PERMISSION_DENIED:
82                 err_str = "SMARTTHINGS_RESOURCE_ERROR_PERMISSION_DENIED";
83                 break;
84         case SMARTTHINGS_RESOURCE_ERROR_NO_DATA:
85                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NO_DATA";
86                 break;
87         case SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED:
88                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED";
89                 break;
90         case SMARTTHINGS_RESOURCE_ERROR_OPERATION_FAILED:
91                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED";
92                 break;
93         case SMARTTHINGS_RESOURCE_ERROR_SERVICE_UNAVAILABLE:
94                 err_str = "SMARTTHINGS_RESOURCE_ERROR_SERVICE_UNAVAILABLE";
95                 break;
96         default:
97                 err_str = "Unknown error";
98                 break;
99         }
100
101         return err_str;
102 }
103
104 static bool
105 handle_get_co2(smartthings_payload_h resp_payload, void *user_data)
106 {
107         app_data *ad = user_data;
108         unsigned int value = 0;
109
110         retv_if(!ad, false);
111
112         sensor_data_get_uint(ad->co2_data, &value);
113         smartthings_payload_set_int(resp_payload, SENSOR_KEY_CO2, (int)value);
114
115         return true;
116 }
117
118 static void
119 _request_cb(smartthings_resource_h handle, int req_id,
120         const char *uri, smartthings_resource_req_type_e req_type,
121         smartthings_payload_h payload, void *user_data)
122 {
123         smartthings_payload_h resp_payload = NULL;
124         bool result = false;
125         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
126
127         _D("request on %s, type[%d], id[%d]", uri, req_type, req_id);
128
129         smartthings_payload_create(&resp_payload);
130         if (!resp_payload) {
131                 _E("Response payload is NULL");
132                 return;
133         }
134
135         if (req_type == SMARTTHINGS_RESOURCE_REQUEST_GET) {
136                 if (0 == g_strcmp0(uri, SENSOR_URI_CO2))
137                         result = handle_get_co2(resp_payload, user_data);
138                 else
139                         _E("No matching Resource uri to get");
140         } else if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
141                         _E("No matching Resource uri to set");
142         } else {
143                 _E("Invalid request type - %d", req_type);
144                 smartthings_payload_destroy(resp_payload);
145                 return;
146         }
147
148         error = smartthings_resource_send_response(handle, req_id, uri, resp_payload, result);
149         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
150                         smartthings_payload_destroy(resp_payload);
151                         _E("smartthings_resource_send_response() failed, [%s]",
152                                 __resource_error_to_str(error));
153                         return;
154         }
155
156         if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
157                         error = smartthings_resource_notify(handle, uri, resp_payload);
158                         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
159                                 _E("smartthings_resource_notify() failed, [%s]",
160                                 __resource_error_to_str(error));
161         }
162
163         if (smartthings_payload_destroy(resp_payload))
164                 _E("smartthings_payload_destroy failed");
165
166         return;
167 }
168
169 static void
170 _resource_connection_status_cb(smartthings_resource_error_e error,
171         smartthings_resource_h handle,
172         smartthings_resource_connection_status_e status, void *user_data)
173 {
174         app_data *ad = user_data;
175
176         _D("result [%s], status=[%d]", __resource_error_to_str(error), status);
177
178         ret_if(!ad);
179
180         ad->st_res_conn_status = status;
181
182         if (status == SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED) {
183                 if (smartthings_resource_set_request_cb(handle, _request_cb, ad)) {
184                         _E("smartthings_resource_set_request_cb() is failed");
185                         return;
186                 }
187         } else {
188                 _E("connection failed");
189         }
190         return;
191 }
192
193 static int
194 st_thing_notify_resource(app_data *ad, const char *uri, const char *key, sensor_data *data)
195 {
196         smartthings_resource_h handle = NULL;
197         smartthings_payload_h payload = NULL;
198         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
199         sensor_data_type_e data_type = SENSOR_DATA_TYPE_NONE;
200
201         retv_if(!ad, -1);
202         retv_if(!ad->st_res_h, -1);
203         retv_if(ad->st_res_conn_status != SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED, -1);
204         retv_if(!uri, -1);
205         retv_if(!key, -1);
206         retv_if(!data, -1);
207
208         handle = ad->st_res_h;
209
210         data_type = sensor_data_get_type(data);
211         retv_if(data_type == SENSOR_DATA_TYPE_NONE, -1);
212
213         smartthings_payload_create(&payload);
214         if (!payload) {
215                 _E("failed to create payload is NULL");
216                 return -1;
217         }
218
219         switch (data_type) {
220         case SENSOR_DATA_TYPE_INT:
221                 {
222                         int value = 0;
223                         sensor_data_get_int(data, &value);
224                         smartthings_payload_set_int(payload, key, value);
225                 }
226                 break;
227         case SENSOR_DATA_TYPE_UINT:
228                 {
229                         unsigned int value = 0;
230                         sensor_data_get_uint(data, &value);
231                         smartthings_payload_set_int(payload, key, (int)value);
232                 }
233                 break;
234         case SENSOR_DATA_TYPE_BOOL:
235                 {
236                         bool value = 0;
237                         sensor_data_get_bool(data, &value);
238                         smartthings_payload_set_bool(payload, key, value);
239                 }
240                 break;
241         case SENSOR_DATA_TYPE_DOUBLE:
242                 {
243                         double value = 0;
244                         sensor_data_get_double(data, &value);
245                         smartthings_payload_set_double(payload, key, value);
246                 }
247                 break;
248         case SENSOR_DATA_TYPE_STR:
249                 {
250                         const char *value = NULL;
251                         sensor_data_get_string(data, &value);
252                         smartthings_payload_set_string(payload, key, value);
253                 }
254                 break;
255         case SENSOR_DATA_TYPE_NONE:
256         default:
257                 _E("unsupport data type");
258                 break;
259         }
260
261         error = smartthings_resource_notify(handle, uri, payload);
262         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
263                 _E("smartthings_resource_notify() failed, [%s]",
264                         __resource_error_to_str(error));
265
266         smartthings_payload_destroy(payload);
267
268         return 0;
269 }
270
271 static int st_thing_resource_init(app_data *ad)
272 {
273         smartthings_resource_h st_res_h = NULL;
274         int error = 0;
275
276         retv_if(!ad, -1);
277         if (ad->st_res_h) {
278                 _I("Already initialized!");
279                 return 0;
280         }
281
282         error = smartthings_resource_initialize(&st_res_h,
283                                 _resource_connection_status_cb, ad);
284         if (error) {
285                 _E("smartthings_resource_initialize() is failed, [%s]",
286                         __resource_error_to_str(error));
287                 return -1;
288         }
289
290         ad->st_res_h = st_res_h;
291         ad->st_res_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
292
293         return 0;
294 }
295
296 static int st_thing_resource_fini(app_data *ad)
297 {
298         retv_if(!ad, -1);
299
300         if (!ad->st_res_h)
301                 return 0;
302
303         smartthings_resource_unset_request_cb(ad->st_res_h);
304         smartthings_resource_deinitialize(ad->st_res_h);
305
306         ad->st_res_h = NULL;
307         ad->st_res_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
308
309         return 0;
310 }
311
312 /* smartthings master functions */
313 static const char *__master_error_to_str(smartthings_error_e error)
314 {
315         const char *err_str = NULL;
316
317         switch (error) {
318         case SMARTTHINGS_ERROR_NONE:
319                 err_str = "SMARTTHINGS_ERROR_NONE";
320                 break;
321         case SMARTTHINGS_ERROR_INVALID_PARAMETER:
322                 err_str = "SMARTTHINGS_ERROR_INVALID_PARAMETER";
323                 break;
324         case SMARTTHINGS_ERROR_OUT_OF_MEMORY:
325                 err_str = "SMARTTHINGS_ERROR_OUT_OF_MEMORY";
326                 break;
327         case SMARTTHINGS_ERROR_PERMISSION_DENIED:
328                 err_str = "SMARTTHINGS_ERROR_PERMISSION_DENIED";
329                 break;
330         case SMARTTHINGS_ERROR_NO_DATA:
331                 err_str = "SMARTTHINGS_ERROR_NO_DATA";
332                 break;
333         case SMARTTHINGS_ERROR_NOT_SUPPORTED:
334                 err_str = "SMARTTHINGS_ERROR_NOT_SUPPORTED";
335                 break;
336         case SMARTTHINGS_ERROR_OPERATION_FAILED:
337                 err_str = "SMARTTHINGS_ERROR_OPERATION_FAILED";
338                 break;
339         case SMARTTHINGS_ERROR_SERVICE_UNAVAILABLE:
340                 err_str = "SMARTTHINGS_ERROR_SERVICE_UNAVAILABLE";
341                 break;
342         default:
343                 err_str = "Unknown error";
344                 break;
345         }
346
347         return err_str;
348 }
349
350 static void _user_confirm_cb(smartthings_h handle, void *user_data)
351 {
352         if (smartthings_send_user_confirm(handle, true) != 0)
353                 _E("smartthings_send_user_confirm() is failed");
354 }
355
356 static void _reset_confirm_cb(smartthings_h handle, void *user_data)
357 {
358         if (smartthings_send_reset_confirm(handle, true) != 0)
359                 _E("smartthings_send_reset_confirm() is failed");
360 }
361
362 static void _reset_result_cb(smartthings_h handle, bool result, void *user_data)
363 {
364         _I("reset result = [%d]", result);
365 }
366
367 static void
368 _thing_status_cb(
369                 smartthings_h handle, smartthings_status_e status, void *user_data)
370 {
371         _D("status: [%d]", status);
372 }
373
374 static void
375 _things_connection_status_cb(smartthings_error_e error,
376         smartthings_h handle, smartthings_connection_status_e status,
377         void *user_data)
378 {
379         _D("result [%s], status = [%d]", __master_error_to_str(error), status);
380
381         if (status == SMARTTHINGS_CONNECTION_STATUS_CONNECTED) {
382                 int err = 0;
383                 bool is_es_completed = false;
384                 const char* dev_name = "co2-app";
385                 int wifi_mode = SMARTTHINGS_WIFI_MODE_11B
386                         | SMARTTHINGS_WIFI_MODE_11G
387                         | SMARTTHINGS_WIFI_MODE_11N;
388
389                 int wifi_freq = SMARTTHINGS_WIFI_FREQ_24G | SMARTTHINGS_WIFI_FREQ_5G;
390
391                 err = smartthings_set_device_property(
392                                         handle, dev_name, wifi_mode, wifi_freq);
393                 if (err) {
394                         _E("smartthings_initialize() is failed, [%s]",
395                                 __master_error_to_str(err));
396                         return;
397                 }
398
399                 err = smartthings_set_certificate_file(handle, CERT_FILE, PRIV_FILE);
400                 if (err) {
401                         _E("smartthings_set_certificate_file() is failed, [%s]",
402                                 __master_error_to_str(err));
403                         return;
404                 }
405
406                 err = smartthings_set_user_confirm_cb(handle, _user_confirm_cb, NULL);
407                 if (err) {
408                         _E("smartthings_set_user_confirm_cb() is failed, [%s]",
409                                 __master_error_to_str(err));
410                         return;
411                 }
412
413                 err = smartthings_set_reset_confirm_cb(handle, _reset_confirm_cb, NULL);
414                 if (err) {
415                         _E("smartthings_set_reset_confirm_cb() is failed, [%s]",
416                                 __master_error_to_str(err));
417                         return;
418                 }
419
420                 err = smartthings_set_reset_result_cb(handle, _reset_result_cb, NULL);
421                 if (err) {
422                         _E("smartthings_set_reset_confirm_cb() is failed, [%s]",
423                                 __master_error_to_str(err));
424                         return;
425                 }
426
427                 err = smartthings_set_status_changed_cb(handle, _thing_status_cb, NULL);
428                 if (err) {
429                         _E("smartthings_set_status_changed_callback() is failed, [%s]",
430                                 __master_error_to_str(err));
431                         return;
432                 }
433
434                 err = smartthings_start(handle);
435                 if (err) {
436                         _E("smartthings_start() is failed, [%s]",
437                                 __master_error_to_str(err));
438                         return;
439                 }
440
441                 err = smartthings_get_easysetup_status(handle, &is_es_completed);
442                 if (err) {
443                         _E("smartthings_get_easysetup_status() is failed, [%s]",
444                                 __master_error_to_str(err));
445                         return;
446                 }
447
448                 if (is_es_completed == true) {
449                         _I("Easysetup is already done");
450                         return;
451                 }
452
453                 err = smartthings_start_easysetup(handle);
454                 if (err) {
455                         _E("smartthings_start_easysetup() is failed, [%s]",
456                                 __master_error_to_str(err));
457                         smartthings_stop(handle);
458                         return;
459                 }
460         } else {
461                         _E("connection failed");
462         }
463         return;
464 }
465
466 static int st_thing_master_init(app_data *ad)
467 {
468         int err = 0;
469         smartthings_h st_handle = NULL;
470
471         retv_if(!ad, -1);
472
473         if (ad->st_master_h) {
474                 _I("Already initialized!");
475                 return 0;
476         }
477
478         err = smartthings_initialize(&st_handle, _things_connection_status_cb, NULL);
479         if (err) {
480                 _E("smartthings_initialize() is failed, [%s]",
481                         __master_error_to_str(err));
482                 return -1;
483         }
484
485         ad->st_master_h = st_handle;
486
487         return 0;
488 }
489
490 int st_thing_master_fini(app_data *ad)
491 {
492         retv_if(!ad, -1);
493
494         if (!ad->st_master_h) {
495                 _I("handle is already NULL");
496                 return 0;
497         }
498
499         smartthings_unset_user_confirm_cb(ad->st_master_h);
500         smartthings_unset_reset_confirm_cb(ad->st_master_h);
501         smartthings_unset_reset_result_cb(ad->st_master_h);
502         smartthings_unset_status_changed_cb(ad->st_master_h);
503
504         smartthings_stop_easysetup(ad->st_master_h);
505         smartthings_stop(ad->st_master_h);
506
507         if (smartthings_deinitialize(ad->st_master_h) != 0)  {
508                 _E("smartthings_deinitialize() is failed");
509                 return -1;
510         }
511         ad->st_master_h = NULL;
512
513         return 0;
514 }
515
516 #endif /* USE_ST_SDK */
517
518 static gboolean __get_co2(gpointer user_data)
519 {
520         int ret = 0;
521         unsigned int value = 0;
522         static unsigned int sum = 0;
523         static unsigned int count = 0;
524
525         app_data *ad = user_data;
526
527         if (!ad) {
528                 _E("failed to get app_data");
529                 service_app_exit();
530                 return FALSE;
531         }
532
533         if (!ad->co2_data) {
534                 _E("failed to get co2_data");
535                 service_app_exit();
536                 ad->getter_co2 = 0;
537                 return FALSE;
538         }
539
540         ret = co2_sensor_read(SENSOR_CH_CO2, &value);
541         retv_if(ret != 0, TRUE);
542
543         count++;
544         sum += value;
545
546         if (count == SENSOR_GATHER_COUNT) {
547                 unsigned int avg = 0;
548                 avg = sum/SENSOR_GATHER_COUNT;
549
550                 _D("co2 avg - [%u], [%u ppm]", avg, co2_sensor_value_to_ppm(avg));
551
552                 sensor_data_set_uint(ad->co2_data, avg);
553
554 #ifdef USE_ST_SDK
555                 st_thing_notify_resource(ad, SENSOR_URI_CO2, SENSOR_KEY_CO2, ad->co2_data);
556 #endif
557                 count = 0;
558                 sum = 0;
559         }
560
561         return TRUE;
562 }
563
564 static void gathering_stop(void *data)
565 {
566         app_data *ad = data;
567         ret_if(!ad);
568
569         if (ad->getter_co2) {
570                 g_source_remove(ad->getter_co2);
571                 ad->getter_co2 = 0;
572         }
573 }
574
575 static void gathering_start(void *data)
576 {
577         app_data *ad = data;
578         ret_if(!ad);
579         ad->getter_co2 = g_timeout_add(SENSOR_GATHER_INTERVAL, __get_co2, ad);
580         if (!ad->getter_co2)
581                 _E("Failed to add getter_co2");
582 }
583
584 static bool service_app_create(void *user_data)
585 {
586         app_data *ad = (app_data *)user_data;
587
588         ad->co2_data = sensor_data_new(SENSOR_DATA_TYPE_UINT);
589         if (!ad->co2_data)
590                 return false;
591
592 #ifdef USE_ST_SDK
593         if (st_thing_master_init(ad))
594                 return false;
595
596         if (st_thing_resource_init(ad)) {
597                 st_thing_master_fini(ad);
598                 return false;
599         }
600 #endif
601
602         return true;
603 }
604
605 static void service_app_control(app_control_h app_control, void *user_data)
606 {
607         gathering_stop(user_data);
608         gathering_start(user_data);
609 }
610
611 static void service_app_terminate(void *user_data)
612 {
613         app_data *ad = (app_data *)user_data;
614
615         if (!ad)
616                 return;
617
618 #ifdef USE_ST_SDK
619         st_thing_resource_fini(ad);
620         st_thing_master_fini(ad);
621 #endif
622
623         sensor_data_free(ad->co2_data);
624         co2_sensor_close();
625         free(ad);
626
627         FN_END;
628 }
629
630 int main(int argc, char *argv[])
631 {
632         app_data *ad = NULL;
633         service_app_lifecycle_callback_s event_callback;
634
635         ad = calloc(1, sizeof(app_data));
636         retv_if(!ad, -1);
637
638         g_ad = ad;
639
640         event_callback.create = service_app_create;
641         event_callback.terminate = service_app_terminate;
642         event_callback.app_control = service_app_control;
643
644         return service_app_main(argc, argv, &event_callback, ad);
645 }
646