Update SmartThings APIs for Tizen 5.0
[apps/native/smart-surveillance-camera.git] / src / st_thing_resource.c
1  /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <smartthings_resource.h>
18 #include <smartthings_payload.h>
19 #include <glib.h>
20 #include "log.h"
21 #include "switch.h"
22 #include "servo-h.h"
23 #include "servo-v.h"
24 #include "motion.h"
25
26 // switch
27 #define URI_SWITCH "/capability/switch/main/0"
28 #define KEY_SWITCH "power"
29 #define VALUE_SWITCH_ON "on"
30 #define VALUE_SWITCH_OFF "off"
31
32 // volume - servo v
33 #define URI_AUDIOVOLUME "/capability/audioVolume/main/0"
34 #define KEY_VOLUME "volume"
35 #define KEY_MUTE "mute"
36
37 // dim switch - servo h
38 #define URI_SWITCHLEVEL "/capability/switchLevel/main/0"
39 #define KEY_SWITCHLEVEL "dimmingSetting"
40
41 // motion
42 #define URI_MOTION "/capability/motionSensor/main/0"
43 #define KEY_MOTION "value"
44
45 #define RESOURCE_CALLBACK_KEY "st_thing_resource"
46
47 static smartthings_resource_h g_st_res_h;
48 static smartthings_resource_connection_status_e g_conn_status =
49                 SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
50
51
52 static const char *
53 __resource_error_to_str(smartthings_resource_error_e error)
54 {
55         const char *err_str = NULL;
56
57         switch (error) {
58         case SMARTTHINGS_RESOURCE_ERROR_NONE:
59                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NONE";
60                 break;
61         case SMARTTHINGS_RESOURCE_ERROR_INVALID_PARAMETER:
62                 err_str = "SMARTTHINGS_RESOURCE_ERROR_INVALID_PARAMETER";
63                 break;
64         case SMARTTHINGS_RESOURCE_ERROR_OUT_OF_MEMORY:
65                 err_str = "SMARTTHINGS_RESOURCE_ERROR_OUT_OF_MEMORY";
66                 break;
67         case SMARTTHINGS_RESOURCE_ERROR_PERMISSION_DENIED:
68                 err_str = "SMARTTHINGS_RESOURCE_ERROR_PERMISSION_DENIED";
69                 break;
70         case SMARTTHINGS_RESOURCE_ERROR_NO_DATA:
71                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NO_DATA";
72                 break;
73         case SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED:
74                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED";
75                 break;
76         case SMARTTHINGS_RESOURCE_ERROR_OPERATION_FAILED:
77                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED";
78                 break;
79         case SMARTTHINGS_RESOURCE_ERROR_SERVICE_UNAVAILABLE:
80                 err_str = "SMARTTHINGS_RESOURCE_ERROR_SERVICE_UNAVAILABLE";
81                 break;
82         default:
83                 err_str = "Unknown error";
84                 break;
85         }
86
87         return err_str;
88 }
89
90 /* get and set request handlers */
91 static bool
92 handle_get_motion(smartthings_payload_h resp_payload, void *user_data)
93 {
94         int state = 0;
95
96         motion_state_get(&state);
97
98         _D("GET request for motion : %d", state);
99         smartthings_payload_set_bool(resp_payload, KEY_MOTION, state ? true : false);
100
101         return true;
102 }
103
104 static bool
105 handle_set_motion(smartthings_payload_h payload,
106         smartthings_payload_h resp_payload, void *user_data)
107 {
108         bool bvalue = 0;
109
110         if (smartthings_payload_get_bool(payload, KEY_MOTION, &bvalue) == 0) {
111                 _D("requested volume: [%d]", bvalue);
112                 motion_state_set((int)bvalue, RESOURCE_CALLBACK_KEY);
113                 smartthings_payload_set_bool(resp_payload, KEY_MOTION, bvalue);
114         }
115
116         return true;
117 }
118
119 static bool
120 handle_get_switch(smartthings_payload_h resp_payload, void *user_data)
121 {
122         switch_state_e state = SWITCH_STATE_OFF;
123         const char *switch_state_name = NULL;
124
125         switch_state_get(&state);
126
127         if (state == SWITCH_STATE_OFF)
128                 switch_state_name = VALUE_SWITCH_OFF;
129         else
130                 switch_state_name = VALUE_SWITCH_ON;
131
132         _D("GET request for switch : %s", switch_state_name);
133         smartthings_payload_set_string(resp_payload, KEY_SWITCH, switch_state_name);
134
135         return true;
136 }
137
138 static bool
139 handle_set_switch(smartthings_payload_h payload,
140         smartthings_payload_h resp_payload, void *user_data)
141 {
142         char *str_value = NULL;
143         switch_state_e state = SWITCH_STATE_OFF;
144
145         if (smartthings_payload_get_string(payload, KEY_SWITCH, &str_value) != 0) {
146                 _E("failed to smartthings_payload_get_string()");
147                 return false;
148         }
149         retv_if(!str_value, false);
150
151         _D("SET request for switch: [%s]", str_value);
152
153         if (0 == g_strcmp0(str_value, VALUE_SWITCH_ON))
154                 state = SWITCH_STATE_ON;
155
156         switch_state_set(state, RESOURCE_CALLBACK_KEY);
157
158         smartthings_payload_set_string(resp_payload, KEY_SWITCH, str_value);
159         free(str_value);
160
161         return true;
162 }
163
164 static bool
165 handle_get_audiovolume(smartthings_payload_h resp_payload, void *user_data)
166 {
167         double value = 0.0f;
168
169         servo_v_state_get(&value);
170
171         _D("current volume: [%f]", value);
172         smartthings_payload_set_int(resp_payload, KEY_VOLUME, (int)value);
173         smartthings_payload_set_bool(resp_payload, KEY_MUTE, false);
174
175         return true;
176 }
177
178 static bool
179 handle_set_audiovolume(smartthings_payload_h payload,
180         smartthings_payload_h resp_payload, void *user_data)
181 {
182         int ivalue = 0;
183
184         if (smartthings_payload_get_int(payload, KEY_VOLUME, &ivalue) == 0) {
185                 _D("requested volume: [%d]", ivalue);
186                 servo_v_state_set((double)ivalue, RESOURCE_CALLBACK_KEY);
187                 smartthings_payload_set_int(resp_payload, KEY_VOLUME, ivalue);
188         }
189
190         smartthings_payload_set_bool(resp_payload, KEY_MUTE, false);
191
192         return true;
193 }
194
195 static bool
196 handle_get_switchLevel(smartthings_payload_h resp_payload, void *user_data)
197 {
198
199         double value = 0;
200
201         servo_h_state_get(&value);
202
203         _D("current switchLevel: [%f]", value);
204         smartthings_payload_set_int(resp_payload, KEY_SWITCHLEVEL, (int)value);
205
206         return true;
207
208 }
209
210 static bool
211 handle_set_switchLevel(smartthings_payload_h payload,
212         smartthings_payload_h resp_payload, void *user_data)
213 {
214         int ivalue = 0;
215
216         if (smartthings_payload_get_int(payload, KEY_SWITCHLEVEL, &ivalue) == 0) {
217                 _D("requested dimming: [%d]", ivalue);
218                 servo_h_state_set((double)ivalue, RESOURCE_CALLBACK_KEY);
219                 smartthings_payload_set_int(resp_payload, KEY_SWITCHLEVEL, ivalue);
220         }
221
222         return true;
223 }
224
225 static void
226 _request_cb(smartthings_resource_h handle, int req_id,
227         const char *uri, smartthings_resource_req_type_e req_type,
228         smartthings_payload_h payload, void *user_data)
229 {
230         smartthings_payload_h resp_payload = NULL;
231         bool result = false;
232         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
233
234         _D("request on %s, type[%d], id[%d]", uri, req_type, req_id);
235
236         smartthings_payload_create(&resp_payload);
237         if (!resp_payload) {
238                 _E("Response payload is NULL");
239                 return;
240         }
241
242         if (req_type == SMARTTHINGS_RESOURCE_REQUEST_GET) {
243                 if (0 == g_strcmp0(uri, URI_SWITCH))
244                         result = handle_get_switch(resp_payload, user_data);
245                 else if (0 == g_strcmp0(uri, URI_AUDIOVOLUME))
246                         result = handle_get_audiovolume(resp_payload, user_data);
247                 else if (0 == g_strcmp0(uri, URI_SWITCHLEVEL))
248                         result = handle_get_switchLevel(resp_payload, user_data);
249                 else if (0 == g_strcmp0(uri, URI_MOTION))
250                         result = handle_get_motion(resp_payload, user_data);
251                 else
252                         _E("No matching Resource uri");
253         } else if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
254                 if (0 == g_strcmp0(uri, URI_SWITCH))
255                         result = handle_set_switch(payload, resp_payload, user_data);
256                 else if (0 == g_strcmp0(uri, URI_AUDIOVOLUME))
257                         result = handle_set_audiovolume(payload, resp_payload, user_data);
258                 else if (0 == g_strcmp0(uri, URI_SWITCHLEVEL))
259                         result = handle_set_switchLevel(payload, resp_payload, user_data);
260                 else if (0 == g_strcmp0(uri, URI_MOTION))
261                         result = handle_set_motion(payload, resp_payload, user_data);
262                 else
263                         _E("No matching Resource uri");
264         } else {
265                 _E("Invalid request type - %d", req_type);
266                 smartthings_payload_destroy(resp_payload);
267                 return;
268         }
269
270         error = smartthings_resource_send_response(handle, req_id, uri, resp_payload, result);
271         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
272                         smartthings_payload_destroy(resp_payload);
273                         _E("smartthings_resource_send_response() failed, [%s]",
274                                 __resource_error_to_str(error));
275                         return;
276         }
277
278         if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
279                         error = smartthings_resource_notify(handle, uri, resp_payload);
280                         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
281                                 _E("smartthings_resource_notify() failed, [%s]",
282                                 __resource_error_to_str(error));
283         }
284
285         if (smartthings_payload_destroy(resp_payload))
286                 _E("smartthings_payload_destroy failed");
287
288         return;
289 }
290
291 static void
292 _resource_connection_status_cb(smartthings_resource_h handle,
293         smartthings_resource_connection_status_e status, void *user_data)
294 {
295         _D("status=[%d]", status);
296
297         g_conn_status = status;
298
299         if (status == SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED) {
300                 if (smartthings_resource_set_request_cb(handle, _request_cb, NULL)) {
301                         _E("smartthings_resource_set_request_cb() is failed");
302                         return;
303                 }
304         } else {
305                 _E("connection failed");
306         }
307         return;
308 }
309
310 static void __motion_changed(int value, void* user_data)
311 {
312         smartthings_resource_h handle = user_data;
313         smartthings_payload_h payload = NULL;
314         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
315
316         ret_if(!handle);
317
318         _D("motion changed to - %d", value);
319
320         ret_if(g_conn_status != SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED);
321
322         smartthings_payload_create(&payload);
323         if (!payload) {
324                 _E("failed to create payload is NULL");
325                 return;
326         }
327
328         smartthings_payload_set_bool(payload, KEY_MOTION, value ? true : false);
329
330         error = smartthings_resource_notify(handle, URI_MOTION, payload);
331         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
332                 _E("smartthings_resource_notify() failed, [%s]",
333                         __resource_error_to_str(error));
334
335         smartthings_payload_destroy(payload);
336 }
337
338 static void __switch_changed(switch_state_e state, void* user_data)
339 {
340         smartthings_resource_h handle = user_data;
341         smartthings_payload_h payload = NULL;
342         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
343         const char *switch_state_name = NULL;
344
345         _D("switch changed to - %d", state);
346         ret_if(!handle);
347         ret_if(g_conn_status != SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED);
348
349         smartthings_payload_create(&payload);
350         if (!payload) {
351                 _E("failed to create payload is NULL");
352                 return;
353         }
354
355         if (state == SWITCH_STATE_OFF)
356                 switch_state_name = VALUE_SWITCH_OFF;
357         else
358                 switch_state_name = VALUE_SWITCH_ON;
359
360         smartthings_payload_set_string(payload, KEY_SWITCH, switch_state_name);
361
362         error = smartthings_resource_notify(handle, URI_SWITCH, payload);
363         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
364                 _E("smartthings_resource_notify() failed, [%s]",
365                         __resource_error_to_str(error));
366
367         smartthings_payload_destroy(payload);
368 }
369
370 static void __servo_v_changed(double value, void* user_data)
371 {
372         smartthings_resource_h handle = user_data;
373         smartthings_payload_h payload = NULL;
374         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
375
376         _D("servo_v changed to - %f", value);
377         ret_if(!handle);
378         ret_if(g_conn_status != SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED);
379
380         smartthings_payload_create(&payload);
381         if (!payload) {
382                 _E("failed to create payload is NULL");
383                 return;
384         }
385
386         smartthings_payload_set_int(payload, KEY_VOLUME, (int)value);
387
388         error = smartthings_resource_notify(handle, URI_AUDIOVOLUME, payload);
389         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
390                 _E("smartthings_resource_notify() failed, [%s]",
391                         __resource_error_to_str(error));
392
393         smartthings_payload_destroy(payload);
394 }
395
396 static void __servo_h_changed(double value, void* user_data)
397 {
398         smartthings_resource_h handle = user_data;
399         smartthings_payload_h payload = NULL;
400         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
401
402         _D("servo_h changed to - %f", value);
403         ret_if(!handle);
404         ret_if(g_conn_status != SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED);
405
406         smartthings_payload_create(&payload);
407         if (!payload) {
408                 _E("failed to create payload is NULL");
409                 return;
410         }
411
412         smartthings_payload_set_int(payload, KEY_SWITCHLEVEL, (int)value);
413
414         error = smartthings_resource_notify(handle, URI_SWITCHLEVEL, payload);
415         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
416                 _E("smartthings_resource_notify() failed, [%s]",
417                         __resource_error_to_str(error));
418
419         smartthings_payload_destroy(payload);
420 }
421
422 static int __device_interfaces_set_callbak(smartthings_resource_h handle)
423 {
424         retv_if(!handle, -1);
425
426         // Assume that, device interfaces are already initialized in controller.c
427         switch_state_changed_cb_set(RESOURCE_CALLBACK_KEY,
428                 __switch_changed, handle);
429         servo_v_state_changed_cb_set(RESOURCE_CALLBACK_KEY,
430                 __servo_v_changed, handle);
431         servo_h_state_changed_cb_set(RESOURCE_CALLBACK_KEY,
432                 __servo_h_changed, handle);
433         motion_state_changed_cb_set(RESOURCE_CALLBACK_KEY,
434                 __motion_changed, handle);
435
436         return 0;
437 }
438
439
440 int st_thing_resource_init(void)
441 {
442         smartthings_resource_h st_res_h = NULL;
443         int error = 0;
444
445         if (g_st_res_h) {
446                 _I("Already initialized!");
447                 return 0;
448         }
449
450         error = smartthings_resource_initialize(&st_res_h,
451                                 _resource_connection_status_cb, NULL);
452         if (error) {
453                 _E("smartthings_resource_initialize() is failed, [%s]",
454                         __resource_error_to_str(error));
455                 return -1;
456         }
457
458         g_st_res_h = st_res_h;
459         g_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
460
461         __device_interfaces_set_callbak(g_st_res_h);
462
463         return 0;
464 }
465
466 int st_thing_resource_fini(void)
467 {
468         if (!g_st_res_h)
469                 return 0;
470
471         smartthings_resource_unset_request_cb(g_st_res_h);
472         smartthings_resource_deinitialize(g_st_res_h);
473         g_st_res_h = NULL;
474         g_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
475
476         return 0;
477 }