9c49b532c5d68fb2c795ceecdea4bcf2c4dc02f9
[apps/native/st-things-blind.git] / src / smart-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 #include <tizen.h>
20 #include <service_app.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <Ecore.h>
26
27 #include "st_things.h"
28 #include "log.h"
29 #include "sensor-data.h"
30 #include "resource.h"
31
32 #define JSON_PATH "device_def.json"
33
34 #define SENSOR_URI_ILLUMINANCE "/capability/illuminanceMeasurement/main/0"
35 #define SENSOR_KEY_ILLUMINANCE "illuminance"
36 #define SENSOR_KEY_RANGE "range"
37
38 #define SENSOR_URI_DOOR "/capability/doorControl/main/0"
39 #define SENSOR_KEY_DOOR "doorState"
40 #define SENSOR_POWER_INITIALIZING BLIND_DOWN
41
42 #define I2C_BUS_NUMBER (1)
43 #define SENSOR_GATHER_INTERVAL (5.0f)
44
45 // If you want to use SmartThings, Please uncomment this define */
46 //#define USE_ST_SDK
47
48 typedef struct app_data_s {
49         Ecore_Timer *getter_illuminance;
50         sensor_data *illuminance_data;
51         sensor_data *power_data;
52 } app_data;
53
54 static app_data *g_ad = NULL;
55
56 #define ILLUMINATION_CRITERIA 1000
57
58 // HS-53 Servo Motor Duty Cycle : 0.54ms ~ 2.1ms
59 // Spec Duty Cycle : 0.553ms ~ 2.227ms(https://www.servocity.com/hitec-hs-53-servo)
60 #define SERVO_MOTOR_DUTY_CYCLE_COUNTER_CLOCKWISE 1.0
61 #define SERVO_MOTOR_DUTY_CYCLE_CLOCKWISE 2.0
62
63 #define BLIND_UP "opening"
64 #define BLIND_DOWN "closing"
65
66 static inline int __get_illuminance(void *data, unsigned int *illuminance_value)
67 {
68         int ret = 0;
69         app_data *ad = data;
70
71         retv_if(!ad, -1);
72         retv_if(!ad->illuminance_data, -1);
73
74         ret = resource_read_illuminance_sensor(I2C_BUS_NUMBER, illuminance_value);
75         retv_if(ret != 0, -1);
76
77         sensor_data_set_uint(ad->illuminance_data, *illuminance_value);
78         _D("Illuminance value : %u", *illuminance_value);
79
80 #ifdef USE_ST_SDK
81         st_things_notify_observers(SENSOR_URI_ILLUMINANCE);
82 #endif
83
84         return 0;
85 }
86
87 static int __set_servo_motor(void *data, int on)
88 {
89         double duty_cycle = 0;
90         int ret = 0;
91         const char *power_value = NULL;
92         app_data *ad = data;
93
94         retv_if(!ad, -1);
95         retv_if(!ad->illuminance_data, -1);
96
97         if (on) {
98                 duty_cycle = SERVO_MOTOR_DUTY_CYCLE_CLOCKWISE;
99                 power_value = BLIND_UP;
100         } else {
101                 duty_cycle = SERVO_MOTOR_DUTY_CYCLE_COUNTER_CLOCKWISE;
102                 power_value = BLIND_DOWN;
103         }
104
105         ret = resource_set_servo_motor_value(duty_cycle);
106         retv_if(ret != 0, -1);
107
108         sensor_data_set_string(ad->power_data, power_value, strlen(power_value));
109
110 #ifdef USE_ST_SDK
111         st_things_notify_observers(SENSOR_URI_DOOR);
112 #endif
113
114         return 0;
115 }
116
117 static Eina_Bool __illuminance_to_servo_motor(void *data)
118 {
119         int ret = 0;
120         unsigned int illuminance_value = 0;
121
122         app_data *ad = data;
123
124         if (!ad) {
125                 _E("failed to get app_data");
126                 service_app_exit();
127         }
128
129         if (!ad->illuminance_data) {
130                 _E("failed to get illuminance_data");
131                 service_app_exit();
132         }
133
134         ret = __get_illuminance(ad, &illuminance_value);
135         retv_if(ret != 0, ECORE_CALLBACK_RENEW);
136
137 #if 1 // If you want to control MOTOR from Cloud, please deactivate these codes.
138         int on = 0;
139
140         if (illuminance_value < ILLUMINATION_CRITERIA) {
141                 on = 0;
142         } else {
143                 on = 1;
144         }
145
146         ret = __set_servo_motor(ad, on);
147         retv_if(ret != 0, ECORE_CALLBACK_RENEW);
148 #endif
149
150         return ECORE_CALLBACK_RENEW;
151 }
152
153 void gathering_stop(void *data)
154 {
155         app_data *ad = data;
156
157         ret_if(!ad);
158
159         if (ad->getter_illuminance)
160                 ecore_timer_del(ad->getter_illuminance);
161 }
162
163 void gathering_start(void *data)
164 {
165         app_data *ad = data;
166
167         ret_if(!ad);
168
169         gathering_stop(ad);
170
171         ad->getter_illuminance = ecore_timer_add(SENSOR_GATHER_INTERVAL, __illuminance_to_servo_motor, ad);
172         if (!ad->getter_illuminance)
173                 _E("Failed to add getter_illuminance");
174 }
175
176 #ifdef USE_ST_SDK
177 static bool handle_reset_request(void)
178 {
179         _D("Received a request for RESET.");
180         return false;
181 }
182
183 static void handle_reset_result(bool result)
184 {
185         _D("Reset %s.\n", result ? "succeeded" : "failed");
186 }
187
188 static bool handle_ownership_transfer_request(void)
189 {
190         _D("Received a request for Ownership-transfer.");
191         return true;
192 }
193
194 static void handle_things_status_change(st_things_status_e things_status)
195 {
196         _D("Things status is changed: %d", things_status);
197
198         if (things_status == ST_THINGS_STATUS_REGISTERED_TO_CLOUD) {
199                 ecore_main_loop_thread_safe_call_async(gathering_start, g_ad);
200         }
201 }
202
203 static bool handle_get_request(st_things_get_request_message_s* req_msg, st_things_representation_s* resp_rep)
204 {
205         _D("resource_uri [%s]", req_msg->resource_uri);
206         retv_if(!g_ad, false);
207
208         if (0 == strcmp(req_msg->resource_uri, SENSOR_URI_ILLUMINANCE)) {
209                 if (req_msg->has_property_key(req_msg, SENSOR_KEY_ILLUMINANCE)) {
210                         unsigned int value = 0;
211                         sensor_data_get_uint(g_ad->illuminance_data, &value);
212                         resp_rep->set_int_value(resp_rep, SENSOR_KEY_ILLUMINANCE, value);
213                 }
214                 return true;
215         } else if (0 == strcmp(req_msg->resource_uri, SENSOR_URI_DOOR)) {
216                 if (req_msg->has_property_key(req_msg, SENSOR_KEY_DOOR)) {
217                         const char *str = NULL;
218                         sensor_data_get_string(g_ad->power_data, &str);
219                         if (!str) {
220                                 str = SENSOR_POWER_INITIALIZING;
221                         }
222                         resp_rep->set_str_value(resp_rep, SENSOR_KEY_DOOR, str);
223                         _D("Power : %s", str);
224                 }
225                 return true;
226         }
227         _E("not supported uri");
228         return false;
229 }
230
231 static bool handle_set_request(st_things_set_request_message_s* req_msg, st_things_representation_s* resp_rep)
232 {
233         _D("resource_uri [%s]", req_msg->resource_uri);
234         retv_if(!g_ad, false);
235
236                 if (0 == strcmp(req_msg->resource_uri, SENSOR_URI_DOOR)) {
237                 int ret = 0;
238                 char *str = NULL;
239
240                 if (req_msg->rep->get_str_value(req_msg->rep, SENSOR_KEY_DOOR, &str)) {
241                         retv_if(!str, false);
242                         _D("set [%s:%s] == %s", SENSOR_URI_DOOR, SENSOR_KEY_DOOR, str);
243
244                         sensor_data_set_string(g_ad->power_data, str, strlen(str));
245                         resp_rep->set_str_value(resp_rep, SENSOR_KEY_DOOR, str);
246
247                         if (0 == strcmp(str, "opening")) {
248                                 ret = __set_servo_motor(g_ad, 1);
249                         } else {
250                                 ret = __set_servo_motor(g_ad, 0);
251                         }
252                         free(str);
253                         retv_if(ret != 0, false);
254                 } else {
255                         _E("cannot get a string value");
256                 }
257
258                 return true;
259         }
260         return false;
261 }
262
263 static int __st_things_init(void)
264 {
265         bool easysetup_complete = false;
266         char app_json_path[128] = {'\0', };
267         char *app_res_path = NULL;
268         char *app_data_path = NULL;
269
270         app_res_path = app_get_resource_path();
271         if (!app_res_path) {
272                 _E("app_res_path is NULL!!");
273                 return -1;
274         }
275
276         app_data_path = app_get_data_path();
277         if (!app_data_path) {
278                 _E("app_data_path is NULL!!");
279                 free(app_res_path);
280                 return -1;
281         }
282
283         snprintf(app_json_path, sizeof(app_json_path), "%s%s", app_res_path, JSON_PATH);
284
285         if (0 != st_things_set_configuration_prefix_path(app_res_path, app_data_path)) {
286                 _E("st_things_set_configuration_prefix_path() failed!!");
287                 free(app_res_path);
288                 free(app_data_path);
289                 return -1;
290         }
291
292         free(app_res_path);
293         free(app_data_path);
294
295         if (0 != st_things_initialize(app_json_path, &easysetup_complete)) {
296                 _E("st_things_initialize() failed!!");
297                 return -1;
298         }
299
300         _D("easysetup_complete:[%d] ", easysetup_complete);
301
302         st_things_register_request_cb(handle_get_request, handle_set_request);
303         st_things_register_reset_cb(handle_reset_request, handle_reset_result);
304         st_things_register_user_confirm_cb(handle_ownership_transfer_request);
305         st_things_register_things_status_change_cb(handle_things_status_change);
306
307         return 0;
308 }
309
310 static int __st_things_deinit(void)
311 {
312         st_things_deinitialize();
313         return 0;
314 }
315
316 static int __st_things_start(void)
317 {
318         st_things_start();
319         return 0;
320 }
321
322 static int __st_things_stop(void)
323 {
324         st_things_stop();
325         return 0;
326 }
327 #endif /* USE_ST_SDK */
328
329 static bool service_app_create(void *user_data)
330 {
331         app_data *ad = (app_data *)user_data;
332
333         ad->illuminance_data = sensor_data_new(SENSOR_DATA_TYPE_UINT);
334         if (!ad->illuminance_data)
335                 return false;
336
337         ad->power_data = sensor_data_new(SENSOR_DATA_TYPE_STR);
338         if (!ad->power_data)
339                 return false;
340         sensor_data_set_string(g_ad->power_data, SENSOR_POWER_INITIALIZING, strlen(SENSOR_POWER_INITIALIZING));
341
342 #ifdef USE_ST_SDK
343         if (__st_things_init())
344                 return false;
345 #endif
346
347         return true;
348 }
349
350 static void service_app_control(app_control_h app_control, void *user_data)
351 {
352 #ifdef USE_ST_SDK
353         __st_things_start();
354 #else
355         gathering_start(user_data);
356 #endif
357 }
358
359 static void service_app_terminate(void *user_data)
360 {
361         app_data *ad = (app_data *)user_data;
362
363         resource_close_illuminance_sensor();
364         resource_close_servo_motor();
365
366 #ifdef USE_ST_SDK
367         __st_things_stop();
368         __st_things_deinit();
369 #else
370         gathering_stop(ad);
371 #endif
372
373         sensor_data_free(ad->illuminance_data);
374         free(ad);
375 }
376
377 int main(int argc, char *argv[])
378 {
379         app_data *ad = NULL;
380         service_app_lifecycle_callback_s event_callback;
381
382         ad = calloc(1, sizeof(app_data));
383         retv_if(!ad, -1);
384
385         g_ad = ad;
386
387         event_callback.create = service_app_create;
388         event_callback.terminate = service_app_terminate;
389         event_callback.app_control = service_app_control;
390
391         return service_app_main(argc, argv, &event_callback, ad);
392 }
393