Use `URI` all caps in documentation
[iotivity.git] / bridging / plugins / lifx_plugin / lifxResource.cpp
1 //******************************************************************
2 //
3 // Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20 //
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <string>
25 #include <fstream>
26 #include <iostream>
27 #include <map>
28 #include <memory>
29 #include <set>
30 #include <cmath>
31 #include <mutex>
32 #include "pluginServer.h"
33 #include "ocpayload.h"
34 #include "oic_malloc.h"
35 #include "oic_string.h"
36 #include "lifx.h"
37 #include "experimental/logger.h"
38 #include "ConcurrentIotivityUtils.h"
39
40 using namespace std;
41
42 MPMPluginCtx *g_pluginCtx = NULL;
43
44 #define DEVICE_NAME "LIFX_BULB"
45 #define DEVICE_TYPE "LIGHT_BULB"
46 #define MANUFACTURER_NAME "LIFX"
47 #define BM 3
48 #define MAX_ACCESS_TOKEN_LENGTH 1024
49 #define TAG "LIFX_RESOURCE"
50
51 static std::string OIC_BINARY_SWITCH = "oic.r.switch.binary";
52 static std::string OIC_BRIGHTNESS_LIGHT = "oic.r.light.brightness";
53 const uint BINARY_SWITCH_CALLBACK = 0;
54 const uint BRIGHTNESS_CALLBACK = 1;
55
56 static const std::string BINARY_SWITCH_RELATIVE_URI = "/switch";
57 static const std::string BRIGHTNESS_RELATIVE_URI = "/brightness";
58
59 std::string accessToken;
60
61 using namespace OC::Bridging;
62
63 typedef struct
64 {
65     char id[MPM_MAX_LENGTH_64];
66     char uuid[MPM_MAX_LENGTH_64];
67     char label[MPM_MAX_LENGTH_64];
68     char user[MPM_MAX_LENGTH_256];
69 } LightDetails;
70
71 std::map<std::string, LifxLightSharedPtr> uriToLifxLightMap;
72 std::map<std::string, LifxLightSharedPtr> addedLights;
73 std::mutex addedLightsLock;
74
75 // Forward declarations.
76 static void *lightMonitorThread(void *pointer);
77 OCEntityHandlerResult resourceEntityHandler(OCEntityHandlerFlag flag,
78         OCEntityHandlerRequest *request, void *callbackParam);
79
80 static LifxLightSharedPtr getLifXLightFromOCFResourceUri(std::string resourceUri);
81
82 FILE *lifxSecurityFile(const char *path, const char *mode)
83 {
84     std::string filename = std::string("lifx_") + path;
85     return fopen(filename.c_str(), mode);
86 }
87
88 MPMResult pluginCreate(MPMPluginCtx **pluginSpecificCtx)
89 {
90     if (g_pluginCtx != NULL)
91     {
92         OIC_LOG(ERROR, TAG, "Plugin is already created.");
93         return MPM_RESULT_ALREADY_CREATED;
94     }
95
96     MPMPluginCtx *ctx = (MPMPluginCtx *) OICCalloc(1, sizeof(MPMPluginCtx));
97
98     if (ctx == NULL)
99     {
100         OIC_LOG(ERROR, TAG, "Allocation of plugin context failed");
101         return MPM_RESULT_INTERNAL_ERROR;
102     }
103
104     *pluginSpecificCtx = ctx;
105     g_pluginCtx = ctx;
106
107     ctx->device_name = "Lifx Translator";
108     ctx->resource_type = "oic.d.light";
109     ctx->open = lifxSecurityFile;
110
111     ifstream tokenFile("./lifx.cnf");
112     if (!tokenFile.is_open())
113     {
114         OIC_LOG(ERROR, TAG, "error loading lifx.cnf file.");
115         return MPM_RESULT_INTERNAL_ERROR;
116     }
117
118     if (!getline (tokenFile, accessToken))
119     {
120         OIC_LOG(ERROR, TAG, "Failed to read ./lifx.cnf");
121         tokenFile.close();
122         return MPM_RESULT_INTERNAL_ERROR;
123     }
124
125     tokenFile.close();
126
127     return MPM_RESULT_OK;
128 }
129
130 MPMResult pluginStart(MPMPluginCtx *ctx)
131 {
132     MPMResult result = MPM_RESULT_INVALID_PARAMETER;
133     int error = 0;
134
135     if (ctx->started)
136     {
137         OIC_LOG(INFO, TAG, "Plugin is already started.");
138         return MPM_RESULT_ALREADY_STARTED;
139     }
140
141     ctx->stay_in_process_loop = true;
142
143     //@todo Maybe move this to plugin_add()? once the first light is added?
144     error = pthread_create(&(ctx->thread_handle), NULL, lightMonitorThread, ctx);
145     if (error == 0)
146     {
147         ctx->started = true;
148         result = MPM_RESULT_OK;
149     }
150     else
151     {
152         OIC_LOG_V(ERROR, TAG, "Can't create plugin specific thread :[%s]", strerror(errno));
153         pluginStop(ctx);
154         result = MPM_RESULT_STARTED_FAILED;
155     }
156
157     OIC_LOG_V(INFO, TAG, "Plugin start return value:%d.", result);
158     return (result);
159 }
160
161 MPMResult pluginScan(MPMPluginCtx *, MPMPipeMessage *)
162 {
163     std::vector<LifxLightSharedPtr> lightsScanned;
164
165     MPMResult result = LifxLight::getLights(accessToken, lightsScanned);
166
167     for (uint32_t i = 0; i < lightsScanned.size(); ++i)
168     {
169         LifxLightSharedPtr light = lightsScanned[i];
170
171         OIC_LOG_V(INFO, TAG, "Found %s bulb %s(%s).", light->state.connected ? "CONNECTED" : "OFFLINE",
172                   light->config.id.c_str(), light->config.label.c_str());
173
174         if (!light->state.connected)
175         {
176             OIC_LOG(INFO, TAG, "Ignoring OFFLINE light");
177             continue;
178         }
179
180         std::string uri = "/lifx/" + light->config.id;
181
182         if (uriToLifxLightMap.find(uri) != uriToLifxLightMap.end())
183         {
184             OIC_LOG_V(INFO, TAG, "Already found %s. Ignoring", uri.c_str());
185             continue;
186         }
187
188         uriToLifxLightMap[uri] = light;
189
190         MPMSendResponse(uri.c_str(), uri.size(), MPM_SCAN);
191     }
192     if (result != MPM_RESULT_OK)
193     {
194         OIC_LOG_V(ERROR, TAG, "Failed to fetch lights with error (%d)", result);
195         return MPM_RESULT_INTERNAL_ERROR;
196     }
197
198     return MPM_RESULT_OK;
199
200 }
201
202 bool isSecureEnvironmentSet()
203 {
204         char *non_secure_env = getenv("NONSECURE");
205
206     if (non_secure_env && !strcmp(non_secure_env, "true"))
207     {
208         OIC_LOG(INFO, TAG, "Creating NON SECURE resources");
209         return false;
210     }
211     OIC_LOG(INFO, TAG, "Creating SECURE resources");
212     return true;
213 }
214
215 MPMResult createPayloadForMetadata(MPMResourceList **list, const std::string &uri, const std::string &res_type,
216                               const std::string &interface)
217 {
218     MPMResourceList *tempPtr;
219     tempPtr = (MPMResourceList *) OICCalloc(1, sizeof(MPMResourceList));
220     if (!tempPtr)
221     {
222         OIC_LOG_V(ERROR, TAG, "failed to allocate memory for tempPtr");
223         return MPM_RESULT_OUT_OF_MEMORY;
224     }
225
226     OICStrcpy(tempPtr->rt, MPM_MAX_LENGTH_64, res_type.c_str());
227     OICStrcpy(tempPtr->href, MPM_MAX_URI_LEN, uri.c_str());
228     OICStrcpy(tempPtr->interfaces, MPM_MAX_LENGTH_64,interface.c_str());
229     tempPtr->bitmap = BM;
230     tempPtr->next = *list;
231     *list  = tempPtr;
232     return MPM_RESULT_OK;
233 }
234
235 /***
236  * Creates 2 OCF resources for a LifxLight. One for the switch to turn it on and off
237  * and one for brightness.
238  *
239  * @param[in] uri Base URI. Switch and brightness URIs are baseUri appended with "/switch" & "/brightness"
240  * @return MPM_RESULT_OK
241  */
242 MPMResult createOCFResources(const std::string &uri)
243 {
244     uint8_t resourceProperties = (OC_OBSERVABLE | OC_DISCOVERABLE);
245     if (isSecureEnvironmentSet())
246     {
247         resourceProperties |= OC_SECURE;
248     }
249
250     std::string switchUri = uri + BINARY_SWITCH_RELATIVE_URI;
251     ConcurrentIotivityUtils::queueCreateResource(switchUri, OIC_BINARY_SWITCH, OC_RSRVD_INTERFACE_ACTUATOR,
252                                             resourceEntityHandler,
253                                             (void *) BINARY_SWITCH_CALLBACK, resourceProperties);
254
255     std::string brightnessUri = uri + BRIGHTNESS_RELATIVE_URI;
256     ConcurrentIotivityUtils::queueCreateResource(brightnessUri, OIC_BRIGHTNESS_LIGHT, OC_RSRVD_INTERFACE_ACTUATOR,
257                                             resourceEntityHandler,
258                                             (void *) BRIGHTNESS_CALLBACK, resourceProperties);
259
260     return MPM_RESULT_OK;
261 }
262
263 MPMResult deleteOCFResources(const std::string &uri)
264 {
265     ConcurrentIotivityUtils::queueDeleteResource(uri + BINARY_SWITCH_RELATIVE_URI);
266     ConcurrentIotivityUtils::queueDeleteResource(uri + BRIGHTNESS_RELATIVE_URI);
267     return MPM_RESULT_OK;
268 }
269
270 MPMResult pluginAdd(MPMPluginCtx *, MPMPipeMessage * message)
271 {
272     if (message->payloadSize <= 0 && message->payload == NULL)
273     {
274         OIC_LOG(ERROR, TAG, "No payload received, failed to add device");
275         return MPM_RESULT_INTERNAL_ERROR;
276     }
277
278     MPMResult result = MPM_RESULT_INTERNAL_ERROR;
279     uint8_t *buff = NULL;
280     MPMResourceList *list = NULL;
281     MPMDeviceSpecificData deviceConfiguration;
282     LightDetails pluginSpecificDetails;
283     std::string user;
284     memset(&pluginSpecificDetails, 0, sizeof(LightDetails));
285     memset(&deviceConfiguration, 0, sizeof(MPMDeviceSpecificData));
286
287     std::string uri = reinterpret_cast<const char*>(message->payload);
288
289     std::lock_guard<std::mutex> lock(addedLightsLock);
290     if (addedLights.find(uri) != addedLights.end())
291     {
292         OIC_LOG_V(ERROR, TAG, "%s already added", uri.c_str());
293         return MPM_RESULT_ALREADY_CREATED;
294     }
295     if (uriToLifxLightMap.find(uri) == uriToLifxLightMap.end())
296     {
297         OIC_LOG_V(ERROR, TAG, "%s was NOT discovered in a scan", uri.c_str());
298         return MPM_RESULT_INTERNAL_ERROR;
299     }
300
301     createOCFResources(uri);
302
303     buff = (uint8_t *)OICCalloc(1, MPM_MAX_METADATA_LEN);
304     if (buff == NULL)
305     {
306         OIC_LOG_V(ERROR, TAG, "Failed to allocate memory for reconnect buffer");
307         return MPM_RESULT_OUT_OF_MEMORY;
308     }
309
310     std::string switchUri = uri + BINARY_SWITCH_RELATIVE_URI;
311     result = createPayloadForMetadata(&list, switchUri, OIC_BINARY_SWITCH,
312                  OC_RSRVD_INTERFACE_ACTUATOR);
313
314     std::string brightnessUri = uri + BRIGHTNESS_RELATIVE_URI;
315     result = createPayloadForMetadata(&list, brightnessUri, OIC_BRIGHTNESS_LIGHT,
316              OC_RSRVD_INTERFACE_ACTUATOR);
317
318     if (result == MPM_RESULT_OUT_OF_MEMORY)
319     {
320         OIC_LOG(ERROR, TAG, "Failed to create payload for metadata");
321         return result;
322     }
323
324     LifxLightSharedPtr targetLight = uriToLifxLightMap[uri];
325     targetLight->getUser(user);
326
327     // filling plugin specific details
328     OICStrcpy(pluginSpecificDetails.id, MPM_MAX_LENGTH_64, targetLight->config.id.c_str());
329     OICStrcpy(pluginSpecificDetails.label, MPM_MAX_LENGTH_64, targetLight->config.label.c_str());
330     OICStrcpy(pluginSpecificDetails.uuid, MPM_MAX_LENGTH_64, targetLight->config.uuid.c_str());
331     OICStrcpy(pluginSpecificDetails.user, MPM_MAX_LENGTH_256, user.c_str());
332
333     // filling device specific details
334     OICStrcpy(deviceConfiguration.devName, MPM_MAX_LENGTH_64, DEVICE_NAME);
335     OICStrcpy(deviceConfiguration.devType, MPM_MAX_LENGTH_64, DEVICE_TYPE);
336     OICStrcpy(deviceConfiguration.manufacturerName, MPM_MAX_LENGTH_256, MANUFACTURER_NAME);
337
338     MPMFormMetaData(list, &deviceConfiguration, buff, MPM_MAX_METADATA_LEN, &pluginSpecificDetails,
339                     sizeof(pluginSpecificDetails));
340
341     addedLights[uri] = uriToLifxLightMap[uri];
342
343     MPMAddResponse response;
344     memset(&response, 0, sizeof(MPMAddResponse));
345     OICStrcpy(response.uri, MPM_MAX_URI_LEN, uri.c_str());
346     memcpy(response.metadata, buff, MPM_MAX_METADATA_LEN);
347
348     size_t size = sizeof(MPMAddResponse);
349
350     MPMSendResponse(&response, size, MPM_ADD);
351
352     OICFree(buff);
353     return result;
354 }
355
356 MPMResult pluginRemove(MPMPluginCtx *, MPMPipeMessage *message)
357 {
358     if (message->payloadSize <= 0 && message->payload == NULL)
359     {
360         OIC_LOG(ERROR, TAG, "No paylaod received, failed to remove device");
361         return MPM_RESULT_INTERNAL_ERROR;
362     }
363     std::string uri = reinterpret_cast<const char *>(message->payload);
364     OIC_LOG_V(DEBUG, TAG, "device uri to be removed - %s ", uri.c_str());
365
366     std::lock_guard<std::mutex> lock(addedLightsLock);
367     if (addedLights.find(uri) == addedLights.end())
368     {
369         OIC_LOG(ERROR, TAG, "Device to be removed is not added yet");
370         return MPM_RESULT_NOT_PRESENT;
371     }
372
373     deleteOCFResources(uri);
374
375     addedLights.erase(uri);
376     uriToLifxLightMap.erase(uri);
377
378     MPMSendResponse(uri.c_str(), uri.size(), MPM_REMOVE);
379     return MPM_RESULT_OK;
380 }
381
382 MPMResult pluginReconnect(MPMPluginCtx *, MPMPipeMessage *message)
383 {
384     MPMResourceList *list = NULL, *temp = NULL;
385     void *pluginSpecificDetails = NULL;
386
387     if (message->payloadSize <= 0 && message->payload == NULL)
388     {
389         OIC_LOG(ERROR, TAG, "No paylaod received, failed to reconnect");
390         return MPM_RESULT_INTERNAL_ERROR;
391     }
392
393     MPMParseMetaData(message->payload, MPM_MAX_METADATA_LEN, &list, &pluginSpecificDetails);
394
395     LightDetails *lightDetails = (LightDetails *)pluginSpecificDetails;
396
397     OIC_LOG_V(DEBUG, TAG, "\n Reconnect Details \nid - %s\nuuid - %s\nlabel - %s\nuser - %s\n",
398               lightDetails->id, lightDetails->uuid, lightDetails->label, lightDetails->user);
399
400     LifxLight::lightState state;
401     LifxLight::lightConfig cfg(lightDetails->id, lightDetails->uuid, lightDetails->label);
402     std::string uri = "/lifx/" + cfg.id;
403     std::shared_ptr<LifxLight> light = std::make_shared<LifxLight>(state, cfg, lightDetails->user);
404
405     createOCFResources(uri);
406     uriToLifxLightMap[uri] = light;
407     addedLights[uri] = uriToLifxLightMap[uri];
408
409     while (list)
410     {
411         temp = list;
412         list = list->next;
413         OICFree(temp);
414     }
415     free(lightDetails);
416     return MPM_RESULT_OK;
417 }
418
419 MPMResult pluginStop(MPMPluginCtx *pluginSpecificCtx)
420 {
421     MPMResult result = MPM_RESULT_OK;
422
423     MPMPluginCtx *ctx = pluginSpecificCtx;
424
425     if (NULL != ctx && g_pluginCtx != NULL)
426     {
427         addedLights.clear();
428         uriToLifxLightMap.clear();
429
430         if (ctx->started)
431         {
432             ctx->stay_in_process_loop = false;
433             pthread_join(ctx->thread_handle, NULL);
434             ctx->started = false;
435         }
436     }
437
438     OIC_LOG_V(INFO, TAG, "Plugin stop's return value:%d", result);
439     return (result);
440
441 }
442
443 MPMResult pluginDestroy(MPMPluginCtx *pluginSpecificCtx)
444 {
445     MPMResult result = MPM_RESULT_INTERNAL_ERROR;
446     MPMPluginCtx *ctx = (MPMPluginCtx *) pluginSpecificCtx;
447
448     if (ctx != NULL && g_pluginCtx != NULL)
449     {
450         if (ctx->started)
451         {
452             pluginStop(pluginSpecificCtx);
453         }
454         // freeing the resource allocated in create
455         OICFree(ctx);
456         g_pluginCtx = NULL;
457         result = MPM_RESULT_OK;
458     }
459
460     OIC_LOG_V(INFO, TAG, "Plugin destroy's return value:%d", result);
461
462     return (result);
463 }
464
465 OCRepPayload *addCommonLifXProperties(const LifxLightSharedPtr &l, OCRepPayload *payload)
466 {
467     if (!OCRepPayloadSetPropString(payload, "x.com.intel.label", l->config.label.c_str()))
468     {
469         throw std::runtime_error("failed to set label");
470     }
471
472     if (!OCRepPayloadSetPropDouble(payload, "x.com.intel.secondsSinceLastSeen",
473                               l->state.secondsSinceLastSeen))
474     {
475         throw std::runtime_error("failed to set secondsSinceLastSeen");
476     }
477     return payload;
478 }
479
480 OCRepPayload *getBinarySwitchPayload(LifxLightSharedPtr l)
481 {
482     std::unique_ptr<OCRepPayload , decltype(OCRepPayloadDestroy) *> payload {OCRepPayloadCreate(),
483          OCRepPayloadDestroy };
484
485     if (!payload)
486     {
487         throw std::runtime_error("payload cannot be NULL");
488     }
489
490     if (!OCRepPayloadSetPropBool(payload.get(), "value", l->state.power))
491     {
492         throw std::runtime_error("failed to set binary switch value in the payload");
493     }
494     return addCommonLifXProperties(l, payload.release());
495 }
496
497 OCRepPayload *getBrightnessPayload(LifxLightSharedPtr l)
498 {
499     std::unique_ptr<OCRepPayload , decltype(OCRepPayloadDestroy) *> payload {OCRepPayloadCreate(),
500              OCRepPayloadDestroy };
501     if (!payload)
502     {
503         throw std::runtime_error("payload cannot be NULL");
504     }
505
506     // Convert LifX [0.0, 1.0] to OCF [0, 100].
507     if (!OCRepPayloadSetPropInt(payload.get(), "brightness", (int64_t) (l->state.brightness * 100.0)))
508     {
509          throw std::runtime_error("failed to set brightness");
510     }
511     return addCommonLifXProperties(l, payload.release());
512
513 }
514
515 OCRepPayload *processGetRequest(LifxLightSharedPtr l, uintptr_t resourceTypeInCallback)
516 {
517     if (resourceTypeInCallback == BINARY_SWITCH_CALLBACK)
518     {
519         return getBinarySwitchPayload(l);
520     }
521     else if (resourceTypeInCallback == BRIGHTNESS_CALLBACK)
522     {
523         return getBrightnessPayload(l);
524     }
525     return NULL;
526 }
527
528 OCEntityHandlerResult processBinarySwitchUpdate(OCRepPayload *payload, LifxLightSharedPtr l)
529 {
530     bool power = false;
531     if (!OCRepPayloadGetPropBool(payload, "value", &power))
532     {
533         throw std::runtime_error("Payload must contain \"value\"");
534     }
535
536     MPMResult result = l->setPower(power);
537
538     if (result != MPM_RESULT_OK)
539     {
540         throw std::runtime_error("Error setting power for PUT request");
541     }
542     return OC_EH_OK;
543 }
544
545 OCEntityHandlerResult processBrightnessUpdate(OCRepPayload *payload, LifxLightSharedPtr l)
546 {
547     int64_t ocfBrightness = 0;
548     if (!OCRepPayloadGetPropInt(payload, "brightness", &ocfBrightness))
549     {
550         throw std::runtime_error("Payload must contain \"brightness\"");
551     }
552     // OCF brightness is [0, 100] and Lifx is [0.0, 1.00]
553     double lifxBrightness = ocfBrightness / 100.0;
554
555     MPMResult result = l->setBrightness(lifxBrightness);
556
557     if (result != MPM_RESULT_OK)
558     {
559         throw std::runtime_error("Error setting brightness for PUT request");
560     }
561     return OC_EH_OK;
562 }
563
564 OCEntityHandlerResult processPutRequest(OCRepPayload *payload, LifxLightSharedPtr l,
565                                         uintptr_t resourceTypeInCallback)
566 {
567     if (payload == NULL)
568     {
569         throw std::runtime_error("PUT payload cannot be NULL");
570     }
571     if (resourceTypeInCallback == BINARY_SWITCH_CALLBACK)
572     {
573         return processBinarySwitchUpdate(payload, l);
574     }
575     else if (resourceTypeInCallback == BRIGHTNESS_CALLBACK)
576     {
577         return processBrightnessUpdate(payload, l);
578     }
579     return OC_EH_OK;
580 }
581
582 static LifxLightSharedPtr getLifXLightFromOCFResourceUri(std::string resourceUri)
583 {
584     OIC_LOG_V(INFO, TAG, "Request for %s", resourceUri.c_str());
585     std::lock_guard<std::mutex> lock(addedLightsLock);
586     for (auto uriToLifXPair : addedLights)
587     {
588         if (resourceUri.find(uriToLifXPair.first) != std::string::npos)
589         {
590             return uriToLifXPair.second;
591         }
592     }
593     throw std::runtime_error("Resource " + resourceUri + " not found");
594 }
595
596 OCEntityHandlerResult resourceEntityHandler(OCEntityHandlerFlag ,
597         OCEntityHandlerRequest *request,
598         void *cb)
599 {
600     uintptr_t callBackParamResourceType = (uintptr_t) cb;
601     OCEntityHandlerResult result = OC_EH_OK;
602     MPMResult res = MPM_RESULT_OK;
603
604     try
605     {
606         std::string uri;
607         ConcurrentIotivityUtils::getUriFromHandle(request->resource, uri);
608
609         LifxLightSharedPtr targetLight = getLifXLightFromOCFResourceUri(uri);
610
611         switch (request->method)
612         {
613             case OC_REST_GET:
614                 // Empty GET case as actual request will be processed after the switch case.
615                 break;
616
617             case OC_REST_PUT:
618             case OC_REST_POST:
619
620                 res = (MPMResult)processPutRequest((OCRepPayload *) request->payload, targetLight,
621                                                    callBackParamResourceType);
622                 if (res != MPM_RESULT_OK)
623                     result = OC_EH_ERROR;
624                 break;
625
626             default:
627                 OIC_LOG_V(INFO, TAG, "Unsupported method (%d) recieved", request->method);
628                 ConcurrentIotivityUtils::respondToRequestWithError(request, "Unsupported method received",
629                         OC_EH_METHOD_NOT_ALLOWED);
630                 return OC_EH_OK;
631         }
632
633         OCRepPayload *responsePayload = processGetRequest(targetLight, callBackParamResourceType);
634         ConcurrentIotivityUtils::respondToRequest(request, responsePayload, result);
635         OCRepPayloadDestroy(responsePayload);
636     }
637     catch (const std::exception &exp)
638     {
639         ConcurrentIotivityUtils::respondToRequestWithError(request, exp.what(), OC_EH_ERROR);
640         return OC_EH_OK;
641     }
642
643     return OC_EH_OK;
644 }
645
646 /* This function does not look for new lights. Only monitors existing lights.
647  * @param[in] pluginSpecificCtx        plugin specific context
648  */
649 void *lightMonitorThread(void *pluginSpecificCtx)
650 {
651     MPMPluginCtx *ctx = (MPMPluginCtx *) pluginSpecificCtx;
652     if (ctx != NULL)
653     {
654         while (ctx->stay_in_process_loop)
655         {
656             addedLightsLock.lock();
657
658             for (auto itr : addedLights)
659             {
660                 LifxLightSharedPtr l = itr.second;
661                 if (!l)
662                 {
663                     continue;
664                 }
665                 LifxLight::lightState oldState = l->state;
666
667                 l->refreshState();
668
669                 LifxLight::lightState newState = l->state;
670
671                 if (oldState.power != newState.power)
672                 {
673                     ConcurrentIotivityUtils::queueNotifyObservers(itr.first + BINARY_SWITCH_RELATIVE_URI);
674                 }
675                 if (fabs(oldState.brightness - newState.brightness) >
676                     0.00001) // Lazy epsilon for double equals check.
677                 {
678                     ConcurrentIotivityUtils::queueNotifyObservers(itr.first + BRIGHTNESS_RELATIVE_URI);
679                 }
680                 if (oldState.connected != newState.connected)
681                 {
682                     OIC_LOG_V(INFO, TAG, "%s is %s", l->config.id.c_str(),
683                               l->state.connected ? "ONLINE" : "OFFLINE");
684                 }
685             }
686
687             addedLightsLock.unlock();
688             sleep(MPM_THREAD_PROCESS_SLEEPTIME);
689         }
690         OIC_LOG(INFO, TAG, "Leaving LIFX monitor thread");
691     }
692     pthread_exit(NULL);
693 }