fix typos
[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_h handle,
171         smartthings_resource_connection_status_e status, void *user_data)
172 {
173         app_data *ad = user_data;
174
175         _D("status=[%d]", status);
176
177         ret_if(!ad);
178
179         ad->st_res_conn_status = status;
180
181         if (status == SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED) {
182                 if (smartthings_resource_set_request_cb(handle, _request_cb, ad)) {
183                         _E("smartthings_resource_set_request_cb() is failed");
184                         return;
185                 }
186         } else {
187                 _E("connection failed");
188         }
189         return;
190 }
191
192 static int
193 st_thing_notify_resource(app_data *ad, const char *uri, const char *key, sensor_data *data)
194 {
195         smartthings_resource_h handle = NULL;
196         smartthings_payload_h payload = NULL;
197         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
198         sensor_data_type_e data_type = SENSOR_DATA_TYPE_NONE;
199
200         retv_if(!ad, -1);
201         retv_if(!ad->st_res_h, -1);
202         retv_if(ad->st_res_conn_status != SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED, -1);
203         retv_if(!uri, -1);
204         retv_if(!key, -1);
205         retv_if(!data, -1);
206
207         handle = ad->st_res_h;
208
209         data_type = sensor_data_get_type(data);
210         retv_if(data_type == SENSOR_DATA_TYPE_NONE, -1);
211
212         smartthings_payload_create(&payload);
213         if (!payload) {
214                 _E("failed to create payload is NULL");
215                 return -1;
216         }
217
218         switch (data_type) {
219         case SENSOR_DATA_TYPE_INT:
220                 {
221                         int value = 0;
222                         sensor_data_get_int(data, &value);
223                         smartthings_payload_set_int(payload, key, value);
224                 }
225                 break;
226         case SENSOR_DATA_TYPE_UINT:
227                 {
228                         unsigned int value = 0;
229                         sensor_data_get_uint(data, &value);
230                         smartthings_payload_set_int(payload, key, (int)value);
231                 }
232                 break;
233         case SENSOR_DATA_TYPE_BOOL:
234                 {
235                         bool value = 0;
236                         sensor_data_get_bool(data, &value);
237                         smartthings_payload_set_bool(payload, key, value);
238                 }
239                 break;
240         case SENSOR_DATA_TYPE_DOUBLE:
241                 {
242                         double value = 0;
243                         sensor_data_get_double(data, &value);
244                         smartthings_payload_set_double(payload, key, value);
245                 }
246                 break;
247         case SENSOR_DATA_TYPE_STR:
248                 {
249                         const char *value = NULL;
250                         sensor_data_get_string(data, &value);
251                         smartthings_payload_set_string(payload, key, value);
252                 }
253                 break;
254         case SENSOR_DATA_TYPE_NONE:
255         default:
256                 _E("unsupport data type");
257                 break;
258         }
259
260         error = smartthings_resource_notify(handle, uri, payload);
261         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
262                 _E("smartthings_resource_notify() failed, [%s]",
263                         __resource_error_to_str(error));
264
265         smartthings_payload_destroy(payload);
266
267         return 0;
268 }
269
270 static int st_thing_resource_init(app_data *ad)
271 {
272         smartthings_resource_h st_res_h = NULL;
273         int error = 0;
274
275         retv_if(!ad, -1);
276         if (ad->st_res_h) {
277                 _I("Already initialized!");
278                 return 0;
279         }
280
281         error = smartthings_resource_initialize(&st_res_h,
282                                 _resource_connection_status_cb, ad);
283         if (error) {
284                 _E("smartthings_resource_initialize() is failed, [%s]",
285                         __resource_error_to_str(error));
286                 return -1;
287         }
288
289         ad->st_res_h = st_res_h;
290         ad->st_res_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
291
292         return 0;
293 }
294
295 static int st_thing_resource_fini(app_data *ad)
296 {
297         retv_if(!ad, -1);
298
299         if (!ad->st_res_h)
300                 return 0;
301
302         smartthings_resource_unset_request_cb(ad->st_res_h);
303         smartthings_resource_deinitialize(ad->st_res_h);
304
305         ad->st_res_h = NULL;
306         ad->st_res_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
307
308         return 0;
309 }
310
311 /* smartthings master functions */
312 static const char *__master_error_to_str(smartthings_error_e error)
313 {
314         const char *err_str = NULL;
315
316         switch (error) {
317         case SMARTTHINGS_ERROR_NONE:
318                 err_str = "SMARTTHINGS_ERROR_NONE";
319                 break;
320         case SMARTTHINGS_ERROR_INVALID_PARAMETER:
321                 err_str = "SMARTTHINGS_ERROR_INVALID_PARAMETER";
322                 break;
323         case SMARTTHINGS_ERROR_OUT_OF_MEMORY:
324                 err_str = "SMARTTHINGS_ERROR_OUT_OF_MEMORY";
325                 break;
326         case SMARTTHINGS_ERROR_PERMISSION_DENIED:
327                 err_str = "SMARTTHINGS_ERROR_PERMISSION_DENIED";
328                 break;
329         case SMARTTHINGS_ERROR_NO_DATA:
330                 err_str = "SMARTTHINGS_ERROR_NO_DATA";
331                 break;
332         case SMARTTHINGS_ERROR_NOT_SUPPORTED:
333                 err_str = "SMARTTHINGS_ERROR_NOT_SUPPORTED";
334                 break;
335         case SMARTTHINGS_ERROR_OPERATION_FAILED:
336                 err_str = "SMARTTHINGS_ERROR_OPERATION_FAILED";
337                 break;
338         case SMARTTHINGS_ERROR_SERVICE_UNAVAILABLE:
339                 err_str = "SMARTTHINGS_ERROR_SERVICE_UNAVAILABLE";
340                 break;
341         default:
342                 err_str = "Unknown error";
343                 break;
344         }
345
346         return err_str;
347 }
348
349 static void _user_confirm_cb(smartthings_h handle, void *user_data)
350 {
351         if (smartthings_send_user_confirm(handle, true) != 0)
352                 _E("smartthings_send_user_confirm() is failed");
353 }
354
355 static void _reset_confirm_cb(smartthings_h handle, void *user_data)
356 {
357         if (smartthings_send_reset_confirm(handle, true) != 0)
358                 _E("smartthings_send_reset_confirm() is failed");
359 }
360
361 static void _reset_result_cb(smartthings_h handle, bool result, void *user_data)
362 {
363         _I("reset result = [%d]", result);
364 }
365
366 static void
367 _thing_status_cb(
368                 smartthings_h handle, smartthings_status_e status, void *user_data)
369 {
370         _D("status: [%d]", status);
371 }
372
373 static void
374 _things_connection_status_cb(smartthings_h handle, smartthings_connection_status_e status,
375         void *user_data)
376 {
377         _D("status = [%d]", status);
378
379         if (status == SMARTTHINGS_CONNECTION_STATUS_CONNECTED) {
380                 int err = 0;
381                 bool is_es_completed = false;
382                 const char* dev_name = "co2-app";
383                 int wifi_mode = SMARTTHINGS_WIFI_MODE_11B
384                         | SMARTTHINGS_WIFI_MODE_11G
385                         | SMARTTHINGS_WIFI_MODE_11N;
386
387                 int wifi_freq = SMARTTHINGS_WIFI_FREQ_24G | SMARTTHINGS_WIFI_FREQ_5G;
388
389                 err = smartthings_set_device_property(
390                                         handle, dev_name, wifi_mode, wifi_freq);
391                 if (err) {
392                         _E("smartthings_initialize() is failed, [%s]",
393                                 __master_error_to_str(err));
394                         return;
395                 }
396
397                 err = smartthings_set_certificate_file(handle, CERT_FILE, PRIV_FILE);
398                 if (err) {
399                         _E("smartthings_set_certificate_file() is failed, [%s]",
400                                 __master_error_to_str(err));
401                         return;
402                 }
403
404                 err = smartthings_set_user_confirm_cb(handle, _user_confirm_cb, NULL);
405                 if (err) {
406                         _E("smartthings_set_user_confirm_cb() is failed, [%s]",
407                                 __master_error_to_str(err));
408                         return;
409                 }
410
411                 err = smartthings_set_reset_confirm_cb(handle, _reset_confirm_cb, NULL);
412                 if (err) {
413                         _E("smartthings_set_reset_confirm_cb() is failed, [%s]",
414                                 __master_error_to_str(err));
415                         return;
416                 }
417
418                 err = smartthings_set_reset_result_cb(handle, _reset_result_cb, NULL);
419                 if (err) {
420                         _E("smartthings_set_reset_confirm_cb() is failed, [%s]",
421                                 __master_error_to_str(err));
422                         return;
423                 }
424
425                 err = smartthings_set_status_changed_cb(handle, _thing_status_cb, NULL);
426                 if (err) {
427                         _E("smartthings_set_status_changed_callback() is failed, [%s]",
428                                 __master_error_to_str(err));
429                         return;
430                 }
431
432                 err = smartthings_start(handle);
433                 if (err) {
434                         _E("smartthings_start() is failed, [%s]",
435                                 __master_error_to_str(err));
436                         return;
437                 }
438
439                 err = smartthings_get_easysetup_status(handle, &is_es_completed);
440                 if (err) {
441                         _E("smartthings_get_easysetup_status() is failed, [%s]",
442                                 __master_error_to_str(err));
443                         return;
444                 }
445
446                 if (is_es_completed == true) {
447                         _I("Easysetup is already done");
448                         return;
449                 }
450
451                 err = smartthings_start_easysetup(handle);
452                 if (err) {
453                         _E("smartthings_start_easysetup() is failed, [%s]",
454                                 __master_error_to_str(err));
455                         smartthings_stop(handle);
456                         return;
457                 }
458         } else {
459                         _E("connection failed");
460         }
461         return;
462 }
463
464 static int st_thing_master_init(app_data *ad)
465 {
466         int err = 0;
467         smartthings_h st_handle = NULL;
468
469         retv_if(!ad, -1);
470
471         if (ad->st_master_h) {
472                 _I("Already initialized!");
473                 return 0;
474         }
475
476         err = smartthings_initialize(&st_handle, _things_connection_status_cb, NULL);
477         if (err) {
478                 _E("smartthings_initialize() is failed, [%s]",
479                         __master_error_to_str(err));
480                 return -1;
481         }
482
483         ad->st_master_h = st_handle;
484
485         return 0;
486 }
487
488 int st_thing_master_fini(app_data *ad)
489 {
490         retv_if(!ad, -1);
491
492         if (!ad->st_master_h) {
493                 _I("handle is already NULL");
494                 return 0;
495         }
496
497         smartthings_unset_user_confirm_cb(ad->st_master_h);
498         smartthings_unset_reset_confirm_cb(ad->st_master_h);
499         smartthings_unset_reset_result_cb(ad->st_master_h);
500         smartthings_unset_status_changed_cb(ad->st_master_h);
501
502         smartthings_stop_easysetup(ad->st_master_h);
503         smartthings_stop(ad->st_master_h);
504
505         if (smartthings_deinitialize(ad->st_master_h) != 0)  {
506                 _E("smartthings_deinitialize() is failed");
507                 return -1;
508         }
509         ad->st_master_h = NULL;
510
511         return 0;
512 }
513
514 #endif /* USE_ST_SDK */
515
516 static gboolean __get_co2(gpointer user_data)
517 {
518         int ret = 0;
519         unsigned int value = 0;
520         static unsigned int sum = 0;
521         static unsigned int count = 0;
522
523         app_data *ad = user_data;
524
525         if (!ad) {
526                 _E("failed to get app_data");
527                 service_app_exit();
528                 return FALSE;
529         }
530
531         if (!ad->co2_data) {
532                 _E("failed to get co2_data");
533                 service_app_exit();
534                 ad->getter_co2 = 0;
535                 return FALSE;
536         }
537
538         ret = co2_sensor_read(SENSOR_CH_CO2, &value);
539         retv_if(ret != 0, TRUE);
540
541         count++;
542         sum += value;
543
544         if (count == SENSOR_GATHER_COUNT) {
545                 unsigned int avg = 0;
546                 avg = sum/SENSOR_GATHER_COUNT;
547
548                 _D("co2 avg - [%u], [%u ppm]", avg, co2_sensor_value_to_ppm(avg));
549
550                 sensor_data_set_uint(ad->co2_data, avg);
551
552 #ifdef USE_ST_SDK
553                 st_thing_notify_resource(ad, SENSOR_URI_CO2, SENSOR_KEY_CO2, ad->co2_data);
554 #endif
555                 count = 0;
556                 sum = 0;
557         }
558
559         return TRUE;
560 }
561
562 static void gathering_stop(void *data)
563 {
564         app_data *ad = data;
565         ret_if(!ad);
566
567         if (ad->getter_co2) {
568                 g_source_remove(ad->getter_co2);
569                 ad->getter_co2 = 0;
570         }
571 }
572
573 static void gathering_start(void *data)
574 {
575         app_data *ad = data;
576         ret_if(!ad);
577         ad->getter_co2 = g_timeout_add(SENSOR_GATHER_INTERVAL, __get_co2, ad);
578         if (!ad->getter_co2)
579                 _E("Failed to add getter_co2");
580 }
581
582 static bool service_app_create(void *user_data)
583 {
584         app_data *ad = (app_data *)user_data;
585
586         ad->co2_data = sensor_data_new(SENSOR_DATA_TYPE_UINT);
587         if (!ad->co2_data)
588                 return false;
589
590 #ifdef USE_ST_SDK
591         if (st_thing_master_init(ad))
592                 return false;
593
594         if (st_thing_resource_init(ad)) {
595                 st_thing_master_fini(ad);
596                 return false;
597         }
598 #endif
599
600         return true;
601 }
602
603 static void service_app_control(app_control_h app_control, void *user_data)
604 {
605         gathering_stop(user_data);
606         gathering_start(user_data);
607 }
608
609 static void service_app_terminate(void *user_data)
610 {
611         app_data *ad = (app_data *)user_data;
612
613         if (!ad)
614                 return;
615
616 #ifdef USE_ST_SDK
617         st_thing_resource_fini(ad);
618         st_thing_master_fini(ad);
619 #endif
620
621         sensor_data_free(ad->co2_data);
622         co2_sensor_close();
623         free(ad);
624
625         FN_END;
626 }
627
628 int main(int argc, char *argv[])
629 {
630         app_data *ad = NULL;
631         service_app_lifecycle_callback_s event_callback;
632
633         ad = calloc(1, sizeof(app_data));
634         retv_if(!ad, -1);
635
636         g_ad = ad;
637
638         event_callback.create = service_app_create;
639         event_callback.terminate = service_app_terminate;
640         event_callback.app_control = service_app_control;
641
642         return service_app_main(argc, argv, &event_callback, ad);
643 }
644