initial upload
[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_error_e error,
293         smartthings_resource_h handle,
294         smartthings_resource_connection_status_e status, void *user_data)
295 {
296         _D("result [%s], status=[%d]", __resource_error_to_str(error), status);
297
298         g_conn_status = status;
299
300         if (status == SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED) {
301                 if (smartthings_resource_set_request_cb(handle, _request_cb, NULL)) {
302                         _E("smartthings_resource_set_request_cb() is failed");
303                         return;
304                 }
305         } else {
306                 _E("connection failed");
307         }
308         return;
309 }
310
311 static void __motion_changed(int value, void* user_data)
312 {
313         smartthings_resource_h handle = user_data;
314         smartthings_payload_h payload = NULL;
315         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
316
317         ret_if(!handle);
318
319         _D("motion changed to - %d", value);
320
321         ret_if(g_conn_status != SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED);
322
323         smartthings_payload_create(&payload);
324         if (!payload) {
325                 _E("failed to create payload is NULL");
326                 return;
327         }
328
329         smartthings_payload_set_bool(payload, KEY_MOTION, value ? true : false);
330
331         error = smartthings_resource_notify(handle, URI_MOTION, payload);
332         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
333                 _E("smartthings_resource_notify() failed, [%s]",
334                         __resource_error_to_str(error));
335
336         smartthings_payload_destroy(payload);
337 }
338
339 static void __switch_changed(switch_state_e state, void* user_data)
340 {
341         smartthings_resource_h handle = user_data;
342         smartthings_payload_h payload = NULL;
343         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
344         const char *switch_state_name = NULL;
345
346         _D("switch changed to - %d", state);
347         ret_if(!handle);
348         ret_if(g_conn_status != SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED);
349
350         smartthings_payload_create(&payload);
351         if (!payload) {
352                 _E("failed to create payload is NULL");
353                 return;
354         }
355
356         if (state == SWITCH_STATE_OFF)
357                 switch_state_name = VALUE_SWITCH_OFF;
358         else
359                 switch_state_name = VALUE_SWITCH_ON;
360
361         smartthings_payload_set_string(payload, KEY_SWITCH, switch_state_name);
362
363         error = smartthings_resource_notify(handle, URI_SWITCH, payload);
364         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
365                 _E("smartthings_resource_notify() failed, [%s]",
366                         __resource_error_to_str(error));
367
368         smartthings_payload_destroy(payload);
369 }
370
371 static void __servo_v_changed(double value, void* user_data)
372 {
373         smartthings_resource_h handle = user_data;
374         smartthings_payload_h payload = NULL;
375         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
376
377         _D("servo_v changed to - %f", value);
378         ret_if(!handle);
379         ret_if(g_conn_status != SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED);
380
381         smartthings_payload_create(&payload);
382         if (!payload) {
383                 _E("failed to create payload is NULL");
384                 return;
385         }
386
387         smartthings_payload_set_int(payload, KEY_VOLUME, (int)value);
388
389         error = smartthings_resource_notify(handle, URI_AUDIOVOLUME, payload);
390         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
391                 _E("smartthings_resource_notify() failed, [%s]",
392                         __resource_error_to_str(error));
393
394         smartthings_payload_destroy(payload);
395 }
396
397 static void __servo_h_changed(double value, void* user_data)
398 {
399         smartthings_resource_h handle = user_data;
400         smartthings_payload_h payload = NULL;
401         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
402
403         _D("servo_h changed to - %f", value);
404         ret_if(!handle);
405         ret_if(g_conn_status != SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED);
406
407         smartthings_payload_create(&payload);
408         if (!payload) {
409                 _E("failed to create payload is NULL");
410                 return;
411         }
412
413         smartthings_payload_set_int(payload, KEY_SWITCHLEVEL, (int)value);
414
415         error = smartthings_resource_notify(handle, URI_SWITCHLEVEL, payload);
416         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
417                 _E("smartthings_resource_notify() failed, [%s]",
418                         __resource_error_to_str(error));
419
420         smartthings_payload_destroy(payload);
421 }
422
423 static int __device_interfaces_set_callbak(smartthings_resource_h handle)
424 {
425         retv_if(!handle, -1);
426
427         // Assume that, device interfaces are already initialized in controller.c
428         switch_state_changed_cb_set(RESOURCE_CALLBACK_KEY,
429                 __switch_changed, handle);
430         servo_v_state_changed_cb_set(RESOURCE_CALLBACK_KEY,
431                 __servo_v_changed, handle);
432         servo_h_state_changed_cb_set(RESOURCE_CALLBACK_KEY,
433                 __servo_h_changed, handle);
434         motion_state_changed_cb_set(RESOURCE_CALLBACK_KEY,
435                 __motion_changed, handle);
436
437         return 0;
438 }
439
440
441 int st_thing_resource_init(void)
442 {
443         smartthings_resource_h st_res_h = NULL;
444         int error = 0;
445
446         if (g_st_res_h) {
447                 _I("Already initialized!");
448                 return 0;
449         }
450
451         error = smartthings_resource_initialize(&st_res_h,
452                                 _resource_connection_status_cb, NULL);
453         if (error) {
454                 _E("smartthings_resource_initialize() is failed, [%s]",
455                         __resource_error_to_str(error));
456                 return -1;
457         }
458
459         g_st_res_h = st_res_h;
460         g_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
461
462         __device_interfaces_set_callbak(g_st_res_h);
463
464         return 0;
465 }
466
467 int st_thing_resource_fini(void)
468 {
469         if (!g_st_res_h)
470                 return 0;
471
472         smartthings_resource_unset_request_cb(g_st_res_h);
473         smartthings_resource_deinitialize(g_st_res_h);
474         g_st_res_h = NULL;
475         g_conn_status = SMARTTHINGS_RESOURCE_CONNECTION_STATUS_DISCONNECTED;
476
477         return 0;
478 }