Initial plugin "Hue Plugin" for bridging project. 61/16861/20
authorskambalx <srikarx.kambaluru@intel.com>
Thu, 23 Feb 2017 12:23:53 +0000 (17:53 +0530)
committerTodd Malsbary <todd.malsbary@intel.com>
Fri, 24 Feb 2017 17:53:10 +0000 (17:53 +0000)
Change-Id: Ia570d82f47d63418433c73adb6cae043264ea48a
Signed-off-by: Joseph Morrow <joseph.l.morrow@intel.com>
Signed-off-by: Gaganpreet Kaur <gaganpreetx.kaur@intel.com>
Signed-off-by: skambalx <srikarx.kambaluru@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/16861
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: Todd Malsbary <todd.malsbary@intel.com>
15 files changed:
bridging/SConscript
bridging/plugins/hue_plugin/README [new file with mode: 0644]
bridging/plugins/hue_plugin/SConscript [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_auth_json.txt [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_auth_spec.cpp [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_auth_spec.h [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_file.cpp [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_file.h [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_objects/hue_bridge.cpp [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_objects/hue_bridge.h [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_objects/hue_defs.h [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_objects/hue_light.cpp [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_objects/hue_light.h [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_resource.cpp [new file with mode: 0644]
bridging/plugins/hue_plugin/hue_resource.h [new file with mode: 0644]

index 0fd62fc..6f51d8c 100644 (file)
@@ -42,7 +42,7 @@ if target_os not in ['android', 'arduino', 'darwin', 'ios', 'tizen', 'msys_nt',
 
     SConscript(os.path.join('plugins', 'lifx_plugin', 'SConscript'))
 
-#    SConscript(os.path.join('plugins', 'hue_plugin', 'SConscript'))
+    SConscript(os.path.join('plugins', 'hue_plugin', 'SConscript'))
 
     SConscript(os.path.join('plugins', 'nest_plugin', 'SConscript'))
 
diff --git a/bridging/plugins/hue_plugin/README b/bridging/plugins/hue_plugin/README
new file mode 100644 (file)
index 0000000..d46c7d4
--- /dev/null
@@ -0,0 +1,70 @@
+General:
+To use this plugin, a config file "hue_auth_json.txt" needs to be populated and placed in
+the same directory as the mpm client (i.e. "mpm_sample_client")
+generated by IoTivity's build system.
+
+Note: A Philips Hue Bridge with a non-proxied internet connection is required along with
+Hue bulbs. Bridge should be connected with ethernet and its ip address we can get from
+router to which the bridge is connected.
+
+
+What should this file look like?
+
+    See sample "hue_auth_json.txt.sample" file with contents as shown
+    below(without spaces, tabs or quotes):
+
+    "
+         [{
+        "id":                 "001788fffe168fe7",¬
+        "username":           "xxxxxxxxxxxxxxxxxxxxx"¬
+         }]
+
+    "
+
+Where to put this file?
+    The placement of the hue_auth_json.txt file should be where
+    your mpm client is also:
+
+    <iotivity>/out/<TARGET_OS>/<TARGET_ARCH>/<BUILD>/bridging/src/mpm_client
+
+    Example: <iotivity>/out/linux/x86_64/release/bridging/src/mpm_client
+        Depending on your build configuration, the path may
+        look mildly different.
+
+What is this username ?
+
+    The username acts like a identity of user for a bridge. Hue API's
+    require this username to find out the devices in the bridge. Each 
+    Bridge can have many usernames associated with it.
+
+Where can I obtain the username ?
+
+    goto https://developers.meethue.com/documentation/getting-started
+    and follow from step3 to obtain Username.
+
+where can I obtain id ?
+
+    id is the Bridge MAC address where u can see at the back panel of the bridge
+    it looks similar like this.. 
+
+    00:17:88:XX:XX:XX
+
+   Append "fffe" after 6 digits from starting without any quotes/tabs/spaces
+   then it looks somewhat like this :
+
+    00:17:88:ff:fe:xx:xx:xx
+
+    Save ur bridge Mac and username as shown above in same format.
+
+
+How can I start this plugin?
+
+    Use binary executable 'mpm_sample_client.
+
+    More information on these clients can be found at
+    <iotivity>/bridging/src/mpm_client/README.
+
+For proper documentation of this plugin, Mini Plugin
+Manager, the client applications, and other plugins, please
+perform a query on the "Bridging" or "Bridging Project" at
+wiki.iotivity.org.
diff --git a/bridging/plugins/hue_plugin/SConscript b/bridging/plugins/hue_plugin/SConscript
new file mode 100644 (file)
index 0000000..01d7f5d
--- /dev/null
@@ -0,0 +1,104 @@
+#******************************************************************
+#
+# Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+##
+# HUE Plugin build script
+##
+
+import os
+import os.path
+
+Import('env')
+
+target_os = env.get('TARGET_OS')
+src_dir = env.get('SRC_DIR')
+bridging_path = os.path.join(src_dir, 'bridging')
+
+hue_env = env.Clone()
+
+SConscript('#/extlibs/cjson/SConscript')
+
+print "Reading Hue Plugin script"
+
+######################################################################
+# Build flags
+######################################################################
+
+def maskFlags(flags):
+    flags = [flags.replace('-Wl,--no-undefined', '' ) for flags in flags]
+    return flags
+
+hue_env.PrependUnique(CPPPATH = [ os.path.join(src_dir, 'resource', 'c_common', 'oic_malloc', 'include'),
+                              os.path.join(src_dir, 'resource', 'c_common', 'oic_string', 'include'),
+                              os.path.join(src_dir, 'resource', 'c_common'),
+                              os.path.join(src_dir, 'resource', 'oc_logger', 'include'),
+                              os.path.join(src_dir, 'resource', 'csdk', 'logger', 'include'),
+                              os.path.join(src_dir, 'resource', 'csdk', 'include'),
+                              os.path.join(src_dir, 'resource', 'csdk', 'stack', 'include'),
+                              os.path.join(src_dir, 'resource', 'include'),
+                              os.path.join(src_dir, 'extlibs', 'cjson'),
+                              os.path.join(src_dir, 'extlibs', 'tinycbor', 'src'),
+                              os.path.join(src_dir, 'extlibs', 'rapidjson', 'rapidjson', 'include', 'rapidjson')
+                              ])
+hue_env.AppendUnique(CPPPATH = [ os.path.join(bridging_path, 'include'),
+                             os.path.join(bridging_path, 'plugins', 'hue_plugin', 'hue_objects')
+                             ])
+
+if target_os not in ['arduino', 'windows']:
+    hue_env.AppendUnique(CPPDEFINES = ['WITH_POSIX'])
+
+if target_os in ['darwin','ios']:
+    hue_env.AppendUnique(CPPDEFINES = ['_DARWIN_C_SOURCE'])
+
+hue_env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-Wextra', '-Werror'])
+hue_env.AppendUnique(RPATH = [hue_env.get('BUILD_DIR')])
+hue_env.AppendUnique(LIBPATH = [hue_env.get('BUILD_DIR')])
+
+if hue_env.get('LOGGING'):
+    hue_env.AppendUnique(CPPDEFINES = ['TB_LOG'])
+
+hue_env['LINKFLAGS'] = maskFlags(env['LINKFLAGS'])
+hue_env.AppendUnique(LINKFLAGS = ['-Wl,--allow-shlib-undefined'])
+hue_env.AppendUnique(LINKFLAGS = ['-Wl,--whole-archive', hue_env.get('BUILD_DIR') +'libmpmcommon.a','-Wl,-no-whole-archive'])
+
+hue_env.AppendUnique(LIBS = ['m',
+                             'cjson',
+                             'octbstack',
+                             'ocsrm',
+                             'connectivity_abstraction',
+                             'coap',
+                             'curl' ])
+
+#####################################################################
+# Source files and Target(s)
+######################################################################
+hue_src = [
+         os.path.join(bridging_path, 'plugins', 'hue_plugin', 'hue_resource.cpp'),
+         os.path.join(bridging_path, 'plugins', 'hue_plugin', 'hue_auth_spec.cpp'),
+         os.path.join(bridging_path, 'plugins', 'hue_plugin', 'hue_file.cpp'),
+         os.path.join(bridging_path, 'plugins', 'hue_plugin', 'hue_objects', 'hue_bridge.cpp'),
+         os.path.join(bridging_path, 'plugins', 'hue_plugin', 'hue_objects', 'hue_light.cpp'),
+         ]
+
+hue_env.AppendUnique(HUE_SRC = hue_src)
+huelib = hue_env.SharedLibrary('hueplugin', hue_env.get('HUE_SRC'))
+hue_env.InstallTarget(huelib, 'hueplugin')
+hue_env.UserInstallTargetLib(huelib, 'hueplugin')
+
+
diff --git a/bridging/plugins/hue_plugin/hue_auth_json.txt b/bridging/plugins/hue_plugin/hue_auth_json.txt
new file mode 100644 (file)
index 0000000..0192c66
--- /dev/null
@@ -0,0 +1,4 @@
+[{
+        "id":                 "001788fffe168fe7",
+        "username":           "newdeveloper"
+}]
diff --git a/bridging/plugins/hue_plugin/hue_auth_spec.cpp b/bridging/plugins/hue_plugin/hue_auth_spec.cpp
new file mode 100644 (file)
index 0000000..8824420
--- /dev/null
@@ -0,0 +1,618 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+#include <mutex>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <regex.h>
+#include "oic_string.h"
+#include "mpmErrorCode.h"
+#include "hue_auth_spec.h"
+#include "hue_file.h"
+#include "hue_defs.h"
+#include "curlClient.h"
+#include "cJSON.h"
+#include "logger.h"
+
+#define TAG "HUE_AUTH"
+
+using namespace OC::Bridging;
+
+/**
+ * This is the global context of the Hue specific authorization module.  There
+ * can only be one instance of this in a process boundary and that is the
+ * case for a decoupled plugin.  So a global context is the best solution. It
+ * is the only global structure required for the implementation of the Hue
+ * specific authorization module.
+ */
+typedef struct HueAuthCtxTag
+{
+    bool structInitialized;
+
+    /** client called the created method */
+    bool created;
+
+    /** store for the client as it is opaque for the authorization module */
+    MPMPluginCtx *pluginCtx;
+
+    /** call back functions on the client */
+    addAuthBridgeCallback addAuthBridge;
+    RemoveAuthBridgeCallback removeAuthBridge;
+
+    pthread_mutex_t discoveredLock;
+} HueAuthCtx;
+
+/**
+ *  NOTE: There is an assumption that global data structures are initialized to 0
+ *       when they are loaded into memory.  If this is not the case then we are
+ *       going have to figure out how to make this behavior happen.  The code
+ *       depends on this structure being set to zero at the beginning of time.
+ */
+HueAuthCtx g_hueAuthCtx;
+
+/**
+ * Global variable for storing discovered bridges and
+ * and mutex lock for it.
+ */
+std::mutex g_discoveredBridgesLock;
+std::vector<HueDiscoveredCtx> g_discoveredBridges;
+
+/**
+ * Function used to initialize the global context.  It depends on the fact
+ * that global variables initialize to all 0s.
+ */
+static void initializeHueAuthCtx();
+
+static MPMResult parseHueBridgeDiscovery(std::string response);
+
+/**
+ * Helper function to parse one bridge out of the discovery response
+ * @param [in] macAddrString  MAC address of the bridge
+ * @param [in] ipAddrString   IP address of the bridge
+ *
+ * @return MPM_RESULT_OK on success else one of the error codes.
+ */
+static MPMResult parseOneHueBridge(char *macAddrString, char *ipAddrString);
+
+/**
+ * Based on a single context structure find a client in the clientID list.
+ *
+ * @param [in] discoveredCtx   Bridge context
+ * @param [in] clientId        Client Id of the bridge
+ *
+ * @return: true  - clientId exists else false
+ */
+static bool discoveredFindClientID(HueDiscoveredCtx *discoveredCtx, const char *clientID);
+
+
+MPMResult hueInit(MPMPluginCtx *ctx, addAuthBridgeCallback addBridgeCb,
+                  RemoveAuthBridgeCallback removeBridgeCb)
+{
+    OIC_LOG(INFO, TAG, " Initializing hue contexts ");
+    initializeHueAuthCtx();
+
+    if ((g_hueAuthCtx.created == false) && (g_hueAuthCtx.structInitialized == true))
+    {
+        g_hueAuthCtx.addAuthBridge = addBridgeCb;
+        g_hueAuthCtx.removeAuthBridge = removeBridgeCb;
+        g_hueAuthCtx.pluginCtx = ctx;
+        g_hueAuthCtx.created = true;
+    }
+    readAuthorizedBridgeFile();
+    return MPM_RESULT_OK;
+}
+
+/**
+ * The intention is to send a request to the Hue bridges on the network to identify
+ * them. This function blindly makes a request for the bridges on a network.  The
+ * doGetReqest is a synchronous function call; so it may take a while.  When
+ * the doGetRequest returns it has a discovery payload which is then parsed
+ * by the parseHueBridgeDiscovery function.  It is in the parsing of each bridge
+ * found where you will see the callbacks to either the authorize module.
+ *
+ * @return MPM_RESULT_OK on success else MPM_RESULT_INTERNAL_ERROR
+ */
+MPMResult DiscoverRemoteBridges()
+{
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+
+    CurlClient cc = CurlClient(CurlClient::CurlMethod::GET, BRIDGE_NUPNP_URI)
+                    .addRequestHeader(CURL_HEADER_ACCEPT_JSON);
+    int curlCode = cc.send();
+    if (curlCode != MPM_RESULT_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, " Error discovering remote HUE Bridges - %d ", curlCode);
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+    else
+    {
+        std::string response = cc.getResponseBody();
+        result = parseHueBridgeDiscovery(response);
+    }
+
+    return (result);
+}
+
+#define UPNP_REQUEST "M-SEARCH * HTTP/1.1\r\n" \
+              "HOST: 239.255.255.250:1900\r\n" \
+              "MAN: \"ssdp:discover\"\r\n" \
+              "MX: 1000\r\n" \
+              "ST: libhue:idl\r\n" \
+              "\r\n"
+
+/**
+ * This finds all Hue Bridges in the local network by sending a multicast
+ * message. No Internet connection is needed.
+ *
+ * The Hue Bridges are using Simple Service Discovery Protocol (SSDP) and
+ * joined the multicast group 239.255.255.250. When I send a SSDP package to
+ * this multicast group all Hue bridges will answer to me with a unicast
+ * message containing their ID (mac address) and I get the IP address from the
+ * normal IP header. Be aware that at least some Hues are answering more than
+ * one time, in my testes I got 3 different answer packages, probably to work
+ * with different (broken) implementations and these were send two times, each
+ * with a little delay, to prevent package loses, combined I got 6 answers from
+ * one Hue bridge to one request. Instead of using a library to create and
+ * parse the SSDP packages, do it manually because we only want to support Hue
+ * bridges and this is a simple protocol, when more features are needed using
+ * a real lib would be better.
+ *
+ * The answer from a Hue bridge with a firmware from October 2015 looks like this:
+ *
+ * HTTP/1.1 200 OK
+ * HOST: 239.255.255.250:1900
+ * EXT:
+ * CACHE-CONTROL: max-age=100
+ * LOCATION: http://192.168.178.241:80/description.xml
+ * SERVER: FreeRTOS/7.4.2 UPnP/1.0 IpBridge/1.10.0
+ * hue-bridgeid: 001788FFFE09A206
+ * ST: upnp:rootdevice
+ * USN: uuid:2f402f80-da50-11e1-9b23-00178809a206::upnp:rootdevice
+ *
+ * source: http://www.developers.meethue.com/documentation/changes-bridge-discovery
+ *
+ * @return MPM_RESULT_OK on success else MPM_RESULT_INTERNAL_ERROR
+ */
+MPMResult DiscoverLocalBridges()
+{
+    int sock;
+    int err;
+    ssize_t len;
+    char recv_buf[500];
+    struct sockaddr_in recv_addr;
+    socklen_t recv_addr_len;
+    struct sockaddr_in address;
+    fd_set rfds;
+    struct timeval tv;
+    regex_t preg;
+    regmatch_t pmatch_id[2];
+    char err_buff[40];
+    char macAddrString[17];
+    int i;
+    unsigned int j;
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+    memset(&address, 0, sizeof(sockaddr_in));
+
+    sock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock == -1)
+    {
+        perror("socket()");
+        OIC_LOG(ERROR, TAG, "socket error");
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+
+    address.sin_family = AF_INET;
+    address.sin_addr.s_addr = inet_addr("239.255.255.250");
+    address.sin_port = htons(1900);
+
+    // send the request to the multicast group  239.255.255.250:1900 the
+    // Hue Bridges are listening to.
+    len = sendto(sock, UPNP_REQUEST, sizeof(UPNP_REQUEST), 0,
+                 (struct sockaddr *) &address, sizeof(address));
+    if (len == -1)
+    {
+        perror("sendto()");
+        OIC_LOG(ERROR, TAG, "sendto() error");
+        goto err_close;
+    }
+
+    // Compile a regular expression to search in the answer message for the
+    // Hue Bridge ID. The answer is send in a text based protocol, one
+    // line is containing an uuid with the mac address at the end. This line
+    // looks like this: "USN: uuid:00112233-4455-6677-8899-aabbccddeeff"
+    err = regcomp(&preg,
+                  "uuid:[0-9a-fA-F]*-[0-9a-fA-F]*-[0-9a-fA-F]*-[0-9a-fA-F]*-([0-9a-fA-F]*)",
+                  REG_EXTENDED);
+    if (err)
+    {
+        regerror(err, &preg, err_buff, sizeof(err_buff));
+        OIC_LOG_V(ERROR, TAG, "problem in regcomp(): %s\n", err_buff);
+        goto err_close;
+    }
+
+    FD_ZERO(&rfds);
+    FD_SET(sock, &rfds);
+
+    tv.tv_sec = 3;
+    tv.tv_usec = 0;
+
+    while (1)
+    {
+        err = select(sock + 1, &rfds, NULL, NULL, &tv);
+        if (err == -1)
+        {
+            OIC_LOG(ERROR, TAG, "error in select()");
+            goto err_regfree;
+        }
+        if (!FD_ISSET(sock, &rfds))
+        {
+            break;
+        }
+
+        // receive the answer package to the multicast request and also
+        // get the address from where we received the package because
+        // we also need the IP-address of the Hue bridge.
+        recv_addr_len = sizeof(recv_addr);
+        memset(&recv_buf, 0x0, sizeof(recv_buf));
+        len = recvfrom(sock, recv_buf, sizeof(recv_buf), 0,
+                       (struct sockaddr *) &recv_addr, &recv_addr_len);
+        if (len == -1)
+        {
+            OIC_LOG(ERROR, TAG, "error in recvfrom()");
+            continue;
+        }
+        // use the compiled regular expression to get the Hue Bridge
+        // ID, the first match is the complete line and the second
+        // match is the mac address we are searching for. We store the
+        // mac address in lower case, so we have to go through it char
+        // by char. After it is parsed add to our internal database.
+        memset(pmatch_id, 0x0, sizeof(pmatch_id));
+        err = regexec(&preg, recv_buf, 2, pmatch_id, 0);
+        if (err)
+        {
+            regerror(err, &preg, err_buff, sizeof(err_buff));
+            OIC_LOG_V(ERROR, TAG, "error in regexec() err_buff=%s", err_buff);
+            continue;
+        }
+        if (pmatch_id[1].rm_so == -1 || pmatch_id[1].rm_eo == -1)
+        {
+            continue;
+        }
+
+        for (i = pmatch_id[1].rm_so, j = 0;
+             i < pmatch_id[1].rm_eo && j < sizeof(macAddrString);
+             i++, j++)
+        {
+            // convert the MAC address into a EUI-64 like it is
+            // done in IPv6.
+            if (j == 6)
+            {
+                macAddrString[j++] = 'f';
+                macAddrString[j++] = 'f';
+                macAddrString[j++] = 'f';
+                macAddrString[j++] = 'e';
+            }
+            macAddrString[j] = tolower(recv_buf[i]);
+        }
+        macAddrString[16] = '\0';
+        result = parseOneHueBridge(macAddrString, inet_ntoa(recv_addr.sin_addr));
+    }
+err_regfree:
+    regfree(&preg);
+err_close:
+    close(sock);
+
+    return (result);
+}
+
+/** discovers both local and remote hue bridges */
+MPMResult DiscoverHueBridges()
+{
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+
+    MPMResult resultRemote = DiscoverRemoteBridges();
+    MPMResult resultLocal = DiscoverLocalBridges();
+
+    //if either discovery was OK, then return result OK.
+    if (resultRemote == MPM_RESULT_OK || resultLocal == MPM_RESULT_OK)
+    {
+        result = MPM_RESULT_OK;
+    }
+    return result;
+}
+
+MPMResult hueAuthGetHttpPrefix(char *prefix, uint32_t *prefixSize, const char *macAddrString,
+                               const char *clientID)
+{
+    MPMResult result = MPM_RESULT_INVALID_PARAMETER;
+    HueDiscoveredCtx discoveredCtx;
+    bool bridgeFound = false;
+    uint32_t size = 0;
+
+    if ((prefix != NULL) && (prefixSize != NULL) && (macAddrString != NULL) && (clientID != NULL))
+    {
+        result = MPM_RESULT_NOT_PRESENT;
+        bridgeFound = findDiscoveredBridge(macAddrString, &discoveredCtx);
+        OIC_LOG_V(DEBUG, TAG, "client id - %s", discoveredCtx.clientIDs);
+        if (bridgeFound == true)
+        {
+            result = MPM_RESULT_NOT_AUTHORIZED;
+            if (discoveredFindClientID(&discoveredCtx, clientID) == true)
+            {
+                result = MPM_RESULT_INSUFFICIENT_BUFFER;
+
+                size = strlen(clientID);
+                size += strlen(discoveredCtx.ipAddrString);
+                size += strlen("/api/");
+                size += 1;
+
+                if (*prefixSize >= size)
+                {
+                    result = MPM_RESULT_OK;
+                    memset(prefix, 0, *prefixSize);
+                    strcpy(prefix, discoveredCtx.ipAddrString);
+                    strcat(prefix, "/api/");
+                    strcat(prefix, clientID);
+                }
+                else
+                {
+                    *prefixSize = size;
+                }
+            }
+        }
+    }
+    return (result);
+}
+
+MPMResult hueAuthDestroy()
+{
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+    if (g_hueAuthCtx.structInitialized == true)
+    {
+        result = MPM_RESULT_OK;
+
+        // Checks all the discovered Bridges and removes the authorized Bridges from the list.
+
+        for (std::vector<HueDiscoveredCtx>::iterator it = g_discoveredBridges.begin() ;
+             it != g_discoveredBridges.end(); ++it)
+        {
+            if (g_hueAuthCtx.removeAuthBridge != NULL)
+            {
+                g_hueAuthCtx.removeAuthBridge((*it).macAddrString);
+            }
+        }
+        g_discoveredBridges.clear();
+    }
+    // wipe the rest of the context
+    memset(&g_hueAuthCtx, 0, sizeof(HueAuthCtx));
+    return (result);
+}
+
+void initializeHueAuthCtx()
+{
+    if (g_hueAuthCtx.structInitialized == false)
+    {
+        memset(&g_hueAuthCtx, 0, sizeof(HueAuthCtx));
+        g_hueAuthCtx.structInitialized = true;
+        if (pthread_mutex_init(&(g_hueAuthCtx.discoveredLock), NULL) != 0)
+        {
+            OIC_LOG(ERROR, TAG, "Unable to initialize global resource mutex.");
+            // The context will stay uninitialized in the error case
+            memset(&g_hueAuthCtx, 0, sizeof(HueAuthCtx));
+        }
+    }
+}
+
+/**
+ * Helper function to parse the discovery and add a bridge to the bridge
+ * list if it is not already there.
+ *
+ * NOTE: parsing data patterns that have the following form
+ *      []
+ *
+ *      [{"id":"001788fffe155cbb","internalipaddress":"172.16.20.133"}]
+ *
+ *      [{"id":"001788fffe155cbb","internalipaddress":"172.16.20.133"},
+ *       {"id":"001788fffe1eeeee","internalipaddress":"172.16.20.134"}]
+ *
+ * @param[in] payload contents of the discovery request.
+ *
+ * @returns MPM_RESULT_OK - parsed ok else MPM_RESULT_ERROR
+ */
+static MPMResult parseHueBridgeDiscovery(std::string payload)
+{
+    MPMResult result = MPM_RESULT_INVALID_PARAMETER;
+    cJSON *object = NULL;
+    cJSON *array = NULL;
+    int32_t numBridges = 0;
+    int32_t index;
+    char *macAddrString = NULL;
+    char *ipAddrString = NULL;
+
+    if (!payload.empty())
+    {
+        result = MPM_RESULT_INTERNAL_ERROR;
+        array = cJSON_Parse((char *) payload.c_str());
+        if (array != NULL)
+        {
+            numBridges = cJSON_GetArraySize(array);
+            for (index = 0; index < numBridges; index++)
+            {
+                object = cJSON_GetArrayItem(array, index);
+                if (object == NULL)
+                {
+                    // if one element is not OK then bail
+                    OIC_LOG(ERROR, TAG, "failed parsing json");
+                    break;
+                }
+                if (cJSON_GetObjectItem(object, "id") != NULL)
+                {
+                    macAddrString = cJSON_GetObjectItem(object, "id")->valuestring;
+                }
+                if (cJSON_GetObjectItem(object, "internalipaddress") != NULL)
+                {
+                    ipAddrString = cJSON_GetObjectItem(object, "internalipaddress")->valuestring;
+                }
+                result = parseOneHueBridge(macAddrString, ipAddrString);
+                if (result != MPM_RESULT_OK)
+                {
+                    // if one element is not OK then bail
+                    break;
+                }
+            }
+            cJSON_Delete(array);
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "array returned from call to cJSON_Parse is NULL.");
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "payload is empty");
+    }
+    return (result);
+}
+
+static MPMResult parseOneHueBridge(char *macAddrString, char *ipAddrString)
+{
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+    HueDiscoveredCtx discoveredCtx;
+    bool bridgeFound = false;
+    bool bridgeAuthorized = false;
+    hueFile fileBridgeCtx;
+    memset(&discoveredCtx, 0, sizeof(HueDiscoveredCtx));
+
+    if ((macAddrString != NULL) && (ipAddrString != NULL))
+    {
+        // Check if bridge is already there in the discovered list
+        bridgeFound = findDiscoveredBridge(macAddrString, &discoveredCtx);
+        if (bridgeFound == false)
+        {
+            OIC_LOG_V(INFO, TAG, "Found bridge %s for the first time", macAddrString);
+
+            // Check if the found bridge is there in the file list. if so then authorize it.
+            bridgeAuthorized = findAuthorizedBridge(macAddrString, NULL, fileBridgeCtx);
+
+            // Build discovered bridge structure to add in the discovered list
+            OICStrcpy(discoveredCtx.macAddrString, MAX_STRING - 1, macAddrString);
+            OICStrcpy(discoveredCtx.ipAddrString, MAX_STRING - 1, ipAddrString);
+
+            // Add the client id of the bridge to discovered list
+            if (bridgeAuthorized == true)
+            {
+                collectAuthorizedClients(macAddrString, (char *) (discoveredCtx.clientIDs),
+                                         &(discoveredCtx.numClients));
+
+                OIC_LOG_V(INFO, TAG, "Added  ClientId to the list = %s ", discoveredCtx.clientIDs);
+            }
+            result = addDiscoveredBridge(discoveredCtx);
+
+            if ((bridgeAuthorized == true) && (g_hueAuthCtx.addAuthBridge != NULL))
+            {
+                g_hueAuthCtx.addAuthBridge(macAddrString, fileBridgeCtx.clientID);
+            }
+        }
+    }
+    else if ((macAddrString == NULL) && (ipAddrString == NULL))
+    {
+        OIC_LOG(INFO, TAG, "this is empty set case []");
+        result = MPM_RESULT_OK;
+    }
+    else
+    {
+        result = MPM_RESULT_INTERNAL_ERROR;
+    }
+    return (result);
+}
+
+MPMResult addDiscoveredBridge(HueDiscoveredCtx discoveredCtx)
+{
+    g_discoveredBridges.push_back(discoveredCtx);
+    return MPM_RESULT_OK;
+}
+
+bool findDiscoveredBridge(const char *macAddrString, HueDiscoveredCtx *discoveredCtx)
+{
+    std::lock_guard<std::mutex> lock(g_discoveredBridgesLock);
+
+    for (std::vector<HueDiscoveredCtx>::iterator it = g_discoveredBridges.begin() ;
+         it != g_discoveredBridges.end(); ++it)
+    {
+        std::string bridge_mac(macAddrString);
+        if (strcmp(bridge_mac.c_str(), (*it).macAddrString) == 0)
+        {
+            *discoveredCtx = *it;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool updateDiscoverBridgeDetails(const char *macAddrString, const char *clientID)
+{
+    std::lock_guard<std::mutex> lock(g_discoveredBridgesLock);
+
+    for (std::vector<HueDiscoveredCtx>::iterator it = g_discoveredBridges.begin() ;
+         it != g_discoveredBridges.end(); ++it)
+    {
+        if ((strcmp(macAddrString, (*it).macAddrString) == 0) && (strcmp((*it).clientIDs, "") == 0))
+        {
+            OICStrcpy((*it).clientIDs, MAX_STRING, clientID);
+            (*it).numClients = 1;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static bool discoveredFindClientID(HueDiscoveredCtx *discoveredCtx, const char *clientID)
+{
+    bool clientFound = false;
+    uint32_t index = 0;
+
+    if ((discoveredCtx != NULL) && (clientID != NULL))
+    {
+        // search an array for the client id.
+        for (index = 0; index < discoveredCtx->numClients; index++)
+        {
+            if (strcmp(&(discoveredCtx->clientIDs[index * MAX_STRING]), clientID) == 0)
+            {
+                clientFound = true;
+                break;
+            }
+            else if (strlen(&(discoveredCtx->clientIDs[index * MAX_STRING])) == 0)
+            {
+                OIC_LOG(ERROR, TAG, " No More Clients in the array ");
+                break;
+            }
+        }
+    }
+    return (clientFound);
+}
diff --git a/bridging/plugins/hue_plugin/hue_auth_spec.h b/bridging/plugins/hue_plugin/hue_auth_spec.h
new file mode 100644 (file)
index 0000000..cbe64eb
--- /dev/null
@@ -0,0 +1,164 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+
+#include <stdint.h>
+#include "pluginServer.h"
+#include "hue_file.h"
+#include <pthread.h>
+
+#ifndef __HUE_AUTH_SPEC_H__
+#define __HUE_AUTH_SPEC_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Each bridge discovered is put into a record which is described below
+ */
+typedef struct HueDiscoveredTag
+{
+    // The client IDs storage will eventually be in a list when we actually figure
+    // out how client applications need to work.  Until we have that data then there
+    // is a client array where index 0 holds the primary client.
+    uint32_t numClients;
+    char clientIDs[MAX_CLIENTS * MAX_STRING];
+    char macAddrString[MAX_STRING];
+    char ipAddrString[MAX_STRING];
+} HueDiscoveredCtx;
+
+
+/**
+ * Callback registered by the HUE plugin back end that allows the plugin specific
+ * authorization code to tell the back end that a new user on a HUE bridge can use the bridge.
+ *
+ * @param[in] *macAddrString In the HUE case this identifier is a 6 byte
+ *                            MAX address of the HUE bridge
+ * @param[in] *clientId      This is a simple string representing the client application that
+ *                            now has permission to use the HUE bridge.
+ */
+typedef void (*addAuthBridgeCallback)(const char *macAddrString, const char *ClientId);
+
+
+/**
+ * Callback registered by the plugin back end which allow the plugin specific
+ * authorization code to remove or revoke a bridge user that tells the back end
+ * that a client can no longer use the bridge.
+ *
+ * @param[in] *macAddrString In the HUE case this identifier is a 6 byte
+ *                           MAX address of the HUE bridge
+ */
+typedef void (*RemoveAuthBridgeCallback)(const char *macAddrString);
+
+
+/**
+ * The intention of this function is to register the callbacks and the
+ * context pointer of the plugin. This function must
+ * only be called once at plugin startup time.
+ *
+ * @param[in] ctx  This is the "back end" context which is considered opaque by the Hue
+ *             authorization implementation code, it has been provided as a convenience
+ *             for the "back end" implementation.
+ * @param[in] FoundBridgeCb  Plugin provides a callback for the authorization implementation for the
+ *                        case where a new user on a bridge is found
+ * @param[in] RemoveBridgeCb Plugin provides a callback for the authorization implementation in the
+ *                       case where a a bridge has been deauthorized
+ * @return MPM_RESULT_OK on Success else MPM_RESULT_CREATED_FAILED.
+ */
+MPMResult hueInit(MPMPluginCtx *ctx, addAuthBridgeCallback foundBridgeCb,
+                  RemoveAuthBridgeCallback removeBridgeCb);
+
+
+/**
+ * Request a discovery of the HUE bridges. Needs to be called at least once, it does
+ * not hurt to call it many times.  Preferably call it the number of times needed.
+ * This is an asyncronous call, the return value tells you if the request got out
+ * and that is all.
+ *
+ * @return MPM_RESULT_OK on Success else MPM_RESULT_INTERNAL_ERROR.
+ */
+MPMResult DiscoverHueBridges();
+
+/**
+ * Helper function to obtain the HTTP prefix string needed for libcurl puts and gets
+ * but more importantly this function tells the plugin if the application and hub are
+ * authorized.
+ *
+ * The macAddr is used to determine which hub  and the clientId is checked to see if
+ * that client application has been authorized to access the bridge.
+ *
+ * @param[in,out]  *prefix        memory where the prefix is written if bridge authorized
+ * @params[in,out] *prefixSize    size of the prefix buffer
+ * @params[in]     *macAddrString mac address string of hue bridge
+ * @params[in]     *clientId      supplied by IoTivity ultimately, another name for this
+ *                                parameter in Iotivity parlance is stack id.
+ * @return on success MPM_RESULT_OK else one of the error codes
+ *
+ */
+MPMResult hueAuthGetHttpPrefix(char *prefix, uint32_t *prefixSize, const char *macAddrString,
+                               const char *clientId);
+
+
+/**
+ * This function does the opposite of creating the Hue Authorization module
+ * it is the last thing called on the Hue Authorization module.
+ *
+ * @returns MPM_RESULT_OK on success else on of the error codes
+ */
+MPMResult hueAuthDestroy();
+
+/**
+ * This functions adds the discovered bridge to the global vector for internal usage
+ * @param[in] discoveredCtx HueDiscoveredCtx structure
+ * @return MPM_RESULT_OK on success else one of the error codes
+ */
+MPMResult addDiscoveredBridge(HueDiscoveredCtx discoveredCtx);
+
+/**
+ * find the bridge from the list based on its MAC
+ *
+ * @param [in]      macAddString   A pointer to an string containing the mac address
+ * @param [in,out]  discoveredCtx  A pointer to empty memory that will be a target for a copy of
+ *                  the found context. Only copies if the context has been found.
+ *
+ * @return true -  bridge context found else false
+ */
+bool findDiscoveredBridge(const char *macAddrString, HueDiscoveredCtx *discoveredCtx);
+
+/*
+ * This functions Updated on of the data of the discovered bridge
+ * to the global vector for internal usage.
+ *
+ * @param[in] macAddrString bridge MAC address
+ * @param[in] clientId Hue Bridge client id
+ *
+ * @return True on success else False
+ */
+bool updateDiscoverBridgeDetails(const char *macAddrString, const char *clientID);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HUE_AUTH_SPEC_H__ */
diff --git a/bridging/plugins/hue_plugin/hue_file.cpp b/bridging/plugins/hue_plugin/hue_file.cpp
new file mode 100644 (file)
index 0000000..4a3e8ab
--- /dev/null
@@ -0,0 +1,236 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <string.h>
+#include "oic_string.h"
+#include "mpmErrorCode.h"
+#include "hue_file.h"
+#include "cJSON.h"
+#include <pthread.h>
+#include <map>
+#include "logger.h"
+
+#define TAG "HUE_FILE"
+
+/**
+ * Parse the authorized bridge array
+ * @param[in] fileBuffer
+ * @param[in] fileBufferSize
+ * @return true if parsed else false
+ */
+static bool parseAuthorizedBridgeArray(char *fileBuffer, uint32_t fileBufferSize);
+
+/**
+ * Parse each authorized bridge to get client and Mac address
+ * @param [in] object
+ * @return true if parsed else false
+ */
+static bool parseAuthorizedBridge(cJSON *object);
+
+std::map<std::string, std::string> file_map;
+
+bool readAuthorizedBridgeFile()
+{
+    bool parsedOk = false;
+    long lSize;
+    char *buffer = NULL;
+    size_t fileResult;
+    FILE *pFile = NULL;
+
+    pFile = fopen(HUE_AUTHORIZATION_FILE, "r");
+    if (pFile == NULL)
+    {
+        OIC_LOG_V(INFO, TAG, "File %s not present",
+                  HUE_AUTHORIZATION_FILE );
+    }
+    else
+    {
+        OIC_LOG_V(INFO, TAG, "Reading auth file @  %s",
+                  HUE_AUTHORIZATION_FILE);
+        // obtain file size:
+        fseek(pFile, 0, SEEK_END);
+        lSize = ftell(pFile);
+        rewind(pFile);
+
+        // allocate memory to contain the whole file:
+        buffer = (char *) malloc(sizeof(char) * (lSize + 1));
+        if ((buffer != NULL) && (lSize > 1))
+        {
+            // copy the file into the buffer:
+            fileResult = fread(buffer, 1, lSize, pFile);
+            if (fileResult == (size_t) lSize)
+            {
+                buffer[lSize] = '\0';
+                OIC_LOG_V(INFO, TAG, "Auth file contents = \n%s\n", buffer);
+                parsedOk = parseAuthorizedBridgeArray(buffer, lSize);
+            }
+        }
+    }
+    if (NULL != buffer)
+    {
+        free(buffer);
+    }
+    if (NULL != pFile)
+    {
+        fclose(pFile);
+    }
+    return (parsedOk);
+}
+
+bool findAuthorizedBridge(const char *macAddrString, const char *clientID, hueFile &bridgeCtx)
+{
+    if ((macAddrString != NULL) && (clientID == NULL))
+    {
+        if (file_map.find(macAddrString) != file_map.end())
+        {
+            std::string clientid = file_map[macAddrString];
+            OICStrcpy(bridgeCtx.clientID, MAX_STRING - 1, clientid.c_str());
+            return true;
+        }
+    }
+    else if ((macAddrString == NULL) && (clientID != NULL))
+    {
+        if (file_map.find(clientID) != file_map.end())
+        {
+            std::string macAddress = file_map[clientID];
+            OICStrcpy(bridgeCtx.macAddrString, MAX_STRING - 1, macAddress.c_str());
+            return true;
+        }
+    }
+    else if ((macAddrString != NULL) && (clientID != NULL))
+    {
+        OICStrcpy(bridgeCtx.macAddrString, MAX_STRING - 1, macAddrString);
+        OICStrcpy(bridgeCtx.clientID, MAX_STRING - 1, clientID);
+        return true;
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Both mac and client id is NULL");
+        return false;
+    }
+    OIC_LOG(ERROR, TAG, "Bridge is not Authorized...........");
+    return false;
+}
+
+static bool parseAuthorizedBridgeArray(char *fileBuffer, uint32_t fileBufferSize)
+{
+    bool parsedOk = false;
+    cJSON *object = NULL;
+    cJSON *array = NULL;
+    int32_t numBridges = 0;
+    int32_t index;
+
+    if ((fileBuffer != NULL) && (fileBufferSize > 0))
+    {
+        array = cJSON_Parse((char *) fileBuffer);
+        if (array != NULL)
+        {
+            numBridges = cJSON_GetArraySize(array);
+            parsedOk = true;
+            for (index = 0; index < numBridges; index++)
+            {
+                object = cJSON_GetArrayItem(array, index);
+                parsedOk = parseAuthorizedBridge(object);
+                if (parsedOk == false)
+                {
+                    OIC_LOG(ERROR, TAG, "Parsing one of the bridge lines in file failed");
+                }
+            }
+            cJSON_Delete(array);
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "array returned from call to cJSON_Parse is NULL.");
+        }
+    }
+    return (parsedOk);
+}
+
+bool addAuthorizedBridge(const char *mac, const char *clientId)
+{
+
+    if (mac == NULL || clientId == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to add the bridge Details to the authorization list");
+        return false;
+    }
+    file_map[mac] = clientId;
+
+    return true;
+}
+
+static bool parseAuthorizedBridge(cJSON *object)
+{
+    char *macAddrString = NULL;
+    char *clientID = NULL;
+
+    if (object != NULL)
+    {
+        if (cJSON_GetObjectItem(object, "id") != NULL)
+        {
+            macAddrString = cJSON_GetObjectItem(object, "id")->valuestring;
+        }
+        if (cJSON_GetObjectItem(object, "username") != NULL)
+        {
+            clientID = cJSON_GetObjectItem(object, "username")->valuestring;
+        }
+
+        addAuthorizedBridge(macAddrString, clientID);
+
+    }
+    return (true);
+}
+
+bool collectAuthorizedClients(const char *macAddrString, char *clientArray, uint32_t *numClients)
+{
+    if ((macAddrString == NULL))
+    {
+        OIC_LOG_V(ERROR, TAG, "Mac id is NULL");
+        return false;
+    }
+    for (std::map<std::string, std::string>::iterator  itr = file_map.begin(); itr != file_map.end();
+         ++itr)
+    {
+        if (strcmp(macAddrString, (*itr).first.c_str()) == 0)
+        {
+            std::string clientID = (*itr).second;
+            if (!clientID.empty())
+            {
+                OICStrcpy(clientArray, MAX_STRING, clientID.c_str());
+            }
+            *numClients = 1;
+            return true;
+        }
+    }
+    return (false);
+}
+
+void clearBridgeDetails()
+{
+    file_map.clear();
+}
+
diff --git a/bridging/plugins/hue_plugin/hue_file.h b/bridging/plugins/hue_plugin/hue_file.h
new file mode 100644 (file)
index 0000000..d2eae82
--- /dev/null
@@ -0,0 +1,110 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+
+#include <stdint.h>
+#include <pthread.h>
+
+#ifndef __HUE_FILE_H__
+#define __HUE_FILE_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+ * defines go here
+ ******************************************************************************/
+
+#define     MAX_CLIENTS                 5
+#define     MAX_STRING                  512
+#define     HUE_AUTHORIZATION_FILE     "hue_auth_json.txt"
+
+typedef struct _hue_file
+{
+    char macAddrString[MAX_STRING];
+    char clientID[MAX_STRING];
+} hueFile;
+
+/**
+ * This API has a create/initialize behavior, it reads all of the
+ * bridge clients contained in a given file into the cached file bridge list.  The
+ * assumption is that this only happens only once when the plugin is loaded.   In
+ * other words (to stess this point); this function should not be called periodically
+ * for the first implementation.
+ *  It has the form as follows:
+ *
+ * {"id":"001788fffe155cbb","username":"A234532444"}
+ *
+ *  @return true if file was read else false
+ */
+bool readAuthorizedBridgeFile();
+
+/**
+ * One can add a bridge file context however one must make sure that the bridge
+ * context is not already in the list.  There should never be two identical
+ * contexts in the list.  One can use the fileFindBridge API to the file
+ * bridge objects in the list prior to adding a bridge client.
+ *
+ * @NOTE: a mac address + client ID constitutes uniqueness of an entry.
+ *
+ * @param[in] macId    MAC Id of the bridge
+ * @param[in] clientId ClientId of the bridge
+ *
+ * @return TRUE if added else FALSE
+ */
+
+bool addAuthorizedBridge(const char *macId, const char *clientId);
+
+/*
+ * Find the file bridge records with the matching mac address and client ID. If
+ * either input is set to NULL, then this routine will return the very first
+ * record where there is a match.  It is not OK to specify both mac address and
+ * client ID as being NULL.
+ *
+ * @param[in] macAddrString   Mac id of the bridge
+ * @param[in] clientID        Clientid of the bridge
+ * @param[in] bridgeCtx
+ *
+ * @return true bridge file record was found else false
+ */
+bool findAuthorizedBridge(const char *macAddrString, const char *clientID, hueFile &bridgeCtx);
+
+void clearBridgeDetails();
+
+/**
+ * Collect Clients strings in an array of strings from records in the file list.
+ * The client array is really a flattened out two dimensional MAX_CLIENTS, MAX_STRING
+ *
+ * @param[in] macAddrString    Mac id of the bridge
+ * @param[in] clientArray      Array of Clientid's of the bridge
+ * @param[in] numClients       no of clients
+ *
+ * @return true if client found else false
+ */
+bool collectAuthorizedClients(const char *macAddrString, char *clientArray, uint32_t *numClients);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HUE_FILE_H__ */
diff --git a/bridging/plugins/hue_plugin/hue_objects/hue_bridge.cpp b/bridging/plugins/hue_plugin/hue_objects/hue_bridge.cpp
new file mode 100644 (file)
index 0000000..2846cac
--- /dev/null
@@ -0,0 +1,165 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+#include "hue_bridge.h"
+#include "curlClient.h"
+#include "logger.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <iostream>
+#include "stringbuffer.h"
+#include "writer.h"
+
+#define TAG "HUE_BRIDGE"
+
+using namespace OC::Bridging;
+HueBridge::HueBridge(hue_bridge_data_t data) :
+    m_bridgeData(data)
+{
+}
+
+HueBridge::~HueBridge()
+{
+    lightsFound.clear();
+}
+
+MPMResult HueBridge::parseBridgeConfig(std::string json)
+{
+    if (json.empty())
+    {
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+    rapidjson::Document doc;
+    doc.SetObject();
+    if (doc.Parse<0>(json.c_str()).HasParseError())
+    {
+        return MPM_RESULT_JSON_ERROR;
+    }
+    if (!JsonHelper::getMember(doc, BRIDGE_NAME, m_bridgeData.name))
+    {
+        OIC_LOG(ERROR, TAG, "Bridge Name is missing " );
+    }
+    if (!JsonHelper::getMember(doc, BRIDGE_ID, m_bridgeData.id))
+    {
+        OIC_LOG(ERROR, TAG, "Bridge id is missing " );
+    }
+    if (!JsonHelper::getMember(doc, BRIDGE_IP, m_bridgeData.ip))
+    {
+        OIC_LOG(ERROR, TAG, "Bridge ip is missing " );
+    }
+    if (!JsonHelper::getMember(doc, BRIDGE_MAC, m_bridgeData.mac))
+    {
+        OIC_LOG(ERROR, TAG, "Bridge Mac is missing " );
+    }
+    if (!JsonHelper::getMember(doc, BRIDGE_SW, m_bridgeData.swVersion))
+    {
+        OIC_LOG(ERROR, TAG, "Bridge SoftWare Version is missing " );
+    }
+    return MPM_RESULT_OK;
+}
+
+MPMResult HueBridge::getBridgeConfigFromCloud()
+{
+    rapidjson::Document doc;
+    std::string discoveryUri;
+
+    discoveryUri = m_curlQuery + "/config";
+    CurlClient cc = CurlClient(CurlClient::CurlMethod::GET, discoveryUri)
+                    .addRequestHeader(CURL_HEADER_ACCEPT_JSON);
+    int curlCode = cc.send();
+    if (curlCode != MPM_RESULT_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "GET request for light failed with error %d", curlCode);
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+    std::string response = cc.getResponseBody();
+
+    if(response.empty())
+    {
+        OIC_LOG(ERROR, TAG, "Config response is empty ");
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+    parseBridgeConfig(response);
+    return MPM_RESULT_OK;
+}
+
+
+MPMResult HueBridge::discoverHueLights()
+{
+    rapidjson::Document doc;
+    std::string discoveryUri;
+
+    discoveryUri = m_curlQuery + "/lights/";
+    CurlClient cc = CurlClient(CurlClient::CurlMethod::GET, discoveryUri)
+                    .addRequestHeader(CURL_HEADER_ACCEPT_JSON);
+    int curlCode = cc.send();
+    if (curlCode != MPM_RESULT_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "GET request for light failed with error %d", curlCode);
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+    std::string response = cc.getResponseBody();
+    doc.SetObject();
+    if (doc.Parse<0>(response.c_str()).HasParseError())
+    {
+        OIC_LOG_V(ERROR, TAG, "Json error in response %s", response.c_str());
+        return MPM_RESULT_JSON_ERROR;
+    }
+
+    if (doc.IsObject())
+    {
+        lightsFound.clear();
+        std::string lightUri;
+        std::string lightData;
+        for (rapidjson::Value::ConstMemberIterator itr = doc.MemberBegin(); itr != doc.MemberEnd(); itr++)
+        {
+            rapidjson::StringBuffer sb;
+            rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
+
+            lightUri = itr->name.GetString();
+            doc[lightUri.c_str()].Accept(writer);
+            lightData = sb.GetString();
+            std::shared_ptr<HueLight> light1 = std::make_shared<HueLight>(discoveryUri + lightUri,
+                                               m_bridgeData.ip, m_bridgeData.id, lightUri, lightData);
+            lightsFound.push_back(light1);
+        }
+    }
+
+    return MPM_RESULT_OK;
+}
+
+/**
+ * returns the lightsFound in lights.
+ *
+ * @param[in,out] lights is a vector that will be copied with the linked lights.
+ */
+
+void HueBridge::getScannedLights(HueLight::lights &lights)
+{
+    lights = lightsFound;
+}
+
+
+void HueBridge::fillLightDetails(std::shared_ptr<HueLight> light)
+{
+    lightsFound.push_back(light);
+}
diff --git a/bridging/plugins/hue_plugin/hue_objects/hue_bridge.h b/bridging/plugins/hue_plugin/hue_objects/hue_bridge.h
new file mode 100644 (file)
index 0000000..cb99e44
--- /dev/null
@@ -0,0 +1,137 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+#ifndef __HUE_BRIDGE_H__
+#define __HUE_BRIDGE_H__
+
+#include <stdio.h>
+#include <vector>
+#include <string>
+#include "hue_light.h"
+#include "JsonHelper.h"
+
+/**
+ * HueBridge class which stores the bridge configuration and associated lights
+ * for each bridge.
+ */
+class HueBridge
+{
+    public:
+        typedef std::vector<std::shared_ptr<HueLight> > lights;
+
+        virtual ~HueBridge();
+
+        typedef struct hue_bridge_data_tag
+        {
+            std::string name;
+            /* Friendly name of the bridge */
+            std::string id;
+            /* Unique ID for the bridge */
+            std::string channel;
+            /* The ZigBee channel in use */
+            std::string mac;
+            /* MAC address of the bridge */
+            std::string ip;
+            /* IP address of the bridge */
+            std::string gateway;
+            /* Gateway IP address */
+            std::string timezone;
+            /* Current / configured timezone */
+            std::string localTime;
+            /* Local time */
+            std::string swVersion;
+            /* Software version */
+            std::string apiVersion; /* API version */
+        } hue_bridge_data_t;
+
+        HueBridge()
+        {
+            m_bridgeData.mac.empty();
+            m_curlQuery.empty();
+            lightsFound.clear();
+        }
+
+        HueBridge(hue_bridge_data_t data);
+
+        HueBridge(std::string data);
+
+        MPMResult parseBridgeConfig(std::string json);
+
+        /**
+         * sets the bridge MAC
+         */
+        void setBridgeMAC(std::string strMac)
+        {
+            m_bridgeData.id = strMac;
+        }
+
+        /**
+         * sets the lib curl query to get the lights associated with the bridge
+         */
+        void setBridgeCurlQuery(std::string strQuery)
+        {
+            m_curlQuery = strQuery;
+        }
+
+        /**
+         * gets the bridge MAC
+         */
+        std::string getBridgeMAC(void)
+        {
+            return  m_bridgeData.id;
+        }
+
+        /**
+         * Queries the hue bridge for the new lights associated with it.
+         *
+         * @return MPM_RESULT_OK on success, or another MPM_RESULT_XXX on error.
+         */
+
+        MPMResult discoverHueLights();
+
+        MPMResult getBridgeConfigFromCloud();
+
+        void getBridgeConfig(hue_bridge_data_t &data)
+        {
+            data = m_bridgeData;
+        }
+
+        /**
+         * Gets all the lights that are associated with the bridge.
+         *
+         * @param[in] huelights is a vector of HueLight instances. Each
+         * one representing a physical light associated with the bridge.
+         */
+        void getScannedLights( HueLight::lights &lights);
+
+
+        void fillLightDetails(std::shared_ptr<HueLight> light);
+
+
+    private:
+        hue_bridge_data_t m_bridgeData;
+        std::string m_curlQuery;
+
+        /*Vector of lights associated with the bridge*/
+        lights lightsFound;
+};
+
+#endif /* __HUE_BRIDGE_H__ */
diff --git a/bridging/plugins/hue_plugin/hue_objects/hue_defs.h b/bridging/plugins/hue_plugin/hue_objects/hue_defs.h
new file mode 100644 (file)
index 0000000..96b3f32
--- /dev/null
@@ -0,0 +1,61 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+#ifndef __HUE_DEFS_H__
+#define __HUE_DEFS_H__
+
+#include <string>
+
+#define HUE_TIMESLICE               2
+
+/**
+ * Constants for the Philiphs Hue Data Model
+ */
+static const std::string DM_STATE_BRI           = "bri";
+static const std::string DM_STATE_SAT           = "sat";
+static const std::string DM_STATE_CSC           = "xy";
+static const std::string DM_STATE_HUE           = "hue";
+static const std::string DM_STATE_POWERED       = "on";
+static const std::string DM_NAME                = "name";
+static const std::string DM_TYPE                = "type";
+static const std::string DM_MODEL_ID            = "modelid";
+static const std::string DM_UNIQUE_ID           = "uniqueid";
+static const std::string DM_VERSION             = "swversion";
+static const std::string DM_STATE               = "state";
+static const std::string DM_STATE_REACHABLE     = "reachable";
+static const std::string DM_STATE_EFFECT        = "effect";
+static const std::string DM_STATE_CT            = "ct";
+static const std::string DM_STATE_ALERT         = "alert";
+static const std::string DM_STATE_COLORMODE     = "colormode";
+static const std::string DM_POINT_SYMBOL        = "pointsymbol";
+
+/**
+ * Bridge Constants
+ */
+static std::string BRIDGE_NUPNP_URI             = "https://www.meethue.com/api/nupnp";
+static const std::string BRIDGE_ID              = "bridgeid";
+static const std::string BRIDGE_IP              = "ipaddress";
+static const std::string BRIDGE_MAC             = "mac";
+static const std::string BRIDGE_NAME            = "name";
+static const std::string BRIDGE_USERNAME        = "mytestapplication";
+static const std::string BRIDGE_SW              = "swversion";
+
+#endif /* __HUE_DEFS_H__ */
diff --git a/bridging/plugins/hue_plugin/hue_objects/hue_light.cpp b/bridging/plugins/hue_plugin/hue_objects/hue_light.cpp
new file mode 100644 (file)
index 0000000..41e7ac6
--- /dev/null
@@ -0,0 +1,313 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+#include "hue_light.h"
+#include <string>
+#include <stdio.h>
+#include <stdlib.h>
+#include <algorithm>
+#include <iostream>
+#include <math.h>
+#include "stringbuffer.h"
+#include "writer.h"
+#include "curlClient.h"
+#include "JsonHelper.h"
+#include "logger.h"
+
+#define TAG "HUE_LIGHT"
+using namespace rapidjson;
+using namespace OC::Bridging;
+
+const std::string HUE_LIGHT_URI = "/light/";
+
+HueLight::HueLight()
+{
+    m_initialized = true;
+    m_uri.empty();
+    m_lastCurlResponse.empty();
+    m_user.empty();
+    m_bridge_ip.empty();
+    m_short_id.empty();
+}
+
+HueLight::HueLight(std::string uri, std::string bridge_ip, std::string bridge_mac,
+                   std::string short_id, std::string json) :
+    m_uri(uri), m_bridge_ip(bridge_ip), m_short_id(short_id), m_initialized(false)
+{
+    m_initialized = true;
+    m_bridge_mac = bridge_mac;
+
+    if (!json.empty())
+    {
+        parseJsonResponse(json);
+    }
+    /*URI - For now URI is in this format /a/light/1, /a/light/2 and so on*/
+    m_config.uri = HUE_LIGHT_URI + m_short_id;
+}
+
+HueLight::~HueLight()
+{
+}
+
+MPMResult HueLight::get()
+{
+    CurlClient cc = CurlClient(CurlClient::CurlMethod::GET, m_uri)
+                    .addRequestHeader(CURL_HEADER_ACCEPT_JSON);
+
+    int curlCode = cc.send();
+
+    if (curlCode != MPM_RESULT_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "GET request for light failed with error %d", curlCode);
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+
+    std::string response = cc.getResponseBody();
+
+    return parseJsonResponse(response);
+}
+
+MPMResult HueLight::parseJsonResponse(std::string json)
+{
+    MPMResult result = MPM_RESULT_OK;
+    rapidjson::Document doc;
+    doc.SetObject();
+    if (doc.Parse<0>(json.c_str()).HasParseError())
+    {
+        return MPM_RESULT_JSON_ERROR;
+    }
+    if (MPM_RESULT_OK != getInternalState(doc) ||
+        MPM_RESULT_OK != getInternalConfig(doc))
+    {
+        result = MPM_RESULT_JSON_ERROR;
+    }
+    return result;
+}
+
+MPMResult HueLight::put(rapidjson::Document &doc)
+{
+    std::string uri = m_uri + "/" + DM_STATE;
+    rapidjson::StringBuffer sb;
+    rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
+    doc.Accept(writer);
+    std::string jsonRequest = sb.GetString();
+
+    CurlClient cc = CurlClient(CurlClient::CurlMethod::PUT, uri)
+                    .addRequestHeader(CURL_HEADER_ACCEPT_JSON)
+                    .setRequestBody(jsonRequest);
+
+    int curlCode = cc.send();
+    std::string response = cc.getResponseBody();
+
+    if (curlCode != MPM_RESULT_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "PUT request for power failed. Error code %d", curlCode);
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+    return MPM_RESULT_OK;
+}
+
+MPMResult HueLight::getInternalState(rapidjson::Document &doc)
+{
+    if (doc.HasMember(DM_STATE.c_str()) && doc[DM_STATE.c_str()].IsObject())
+    {
+        for (Value::ConstMemberIterator it = doc[DM_STATE.c_str()].MemberBegin();
+             it != doc[DM_STATE.c_str()].MemberEnd(); it++)
+        {
+            if (!strcmp(it->name.GetString(), DM_STATE_POWERED.c_str()))
+            {
+                m_state.power = it->value.GetBool();
+            }
+            else if (!strcmp(it->name.GetString(), DM_STATE_HUE.c_str()))
+            {
+                m_state.hue = it->value.GetInt();
+            }
+            else if (!strcmp(it->name.GetString(), DM_STATE_BRI.c_str()))
+            {
+                m_state.bri = it->value.GetInt();
+            }
+            else if (!strcmp(it->name.GetString(), DM_STATE_SAT.c_str()))
+            {
+                m_state.sat = it->value.GetInt();
+            }
+            else if (!strcmp(it->name.GetString(), DM_STATE_REACHABLE.c_str()))
+            {
+                m_state.reachable = it->value.GetBool();
+            }
+            else if (!strcmp(it->name.GetString(), DM_STATE_COLORMODE.c_str()))
+            {
+                m_state.colorMode = it->value.GetString();
+            }
+            else if (!strcmp(it->name.GetString(), DM_STATE_ALERT.c_str()))
+            {
+                m_state.alert = it->value.GetString();
+            }
+            else if (!strcmp(it->name.GetString(), DM_STATE_CT.c_str()))
+            {
+                m_state.ct = it->value.GetUint();
+            }
+            else if (!strcmp(it->name.GetString(), DM_STATE_CSC.c_str()))
+            {
+
+                const Value &csc_xy = it->value;
+                for (SizeType i = 0; i < csc_xy.Size(); i++)
+                {
+
+                    // A third element for "xy" is weird. Defensive if here.
+                    if (i >= 2)
+                    { break; }
+                    m_state.csc[i] = csc_xy[i].GetDouble();
+                }
+            }
+        }
+
+    }
+    else
+    {
+        return MPM_RESULT_JSON_ERROR;
+    }
+    return MPM_RESULT_OK;
+}
+
+/**
+ * Generates URI for this resource using the bridge's IP address and resource's unique id
+ * All of the URIs for the HUE resources begin with /a/light/.
+ * If multiple bridges are discoverd the bridge_ip will give the uniqueness to the URI
+ * URI example for light 1 : /a/light/192.168.1.120/1
+ * NOTE: today we are not concerned with the URI size, however, in the future we may have to change
+ * the size of unique string.
+ *
+ */
+std::string HueLight::generateURI()
+{
+    return HUE_LIGHT_URI + m_short_id;
+}
+
+
+MPMResult HueLight::getInternalConfig(rapidjson::Document &doc)
+{
+    if (!JsonHelper::getMember(doc, DM_TYPE, m_config.type))
+    {
+        OIC_LOG(INFO, TAG, "config type is missing");
+    }
+    if (!JsonHelper::getMember(doc, DM_NAME, m_config.name))
+    {
+        OIC_LOG(INFO, TAG, "config  name is missing");
+    }
+    if (!JsonHelper::getMember(doc, DM_MODEL_ID, m_config.modelId))
+    {
+        OIC_LOG(INFO, TAG, "config modelId is missing");
+    }
+    if (!JsonHelper::getMember(doc, DM_UNIQUE_ID, m_config.uniqueId))
+    {
+        OIC_LOG(INFO, TAG, "config uniqueId is missing");
+    }
+    if (!JsonHelper::getMember(doc, DM_VERSION, m_config.swversion))
+    {
+        OIC_LOG(INFO, TAG, "config swversion is missing");
+    }
+    return MPM_RESULT_OK;
+}
+
+MPMResult HueLight::getState(light_state_t &state, bool refresh)
+{
+    MPMResult result = MPM_RESULT_OK;
+    if (m_initialized)
+    {
+        if (refresh == true)
+        {
+            result = get();
+        }
+        if (result == MPM_RESULT_OK)
+        {
+            /* this is a structure copy */
+            state = m_state;
+        }
+    }
+    else
+    {
+        result = MPM_RESULT_INVALID_DATA;
+    }
+    return result;
+}
+
+MPMResult HueLight::setState(light_state_t &state)
+{
+    MPMResult result = MPM_RESULT_INVALID_DATA;
+    if (m_initialized)
+    {
+        rapidjson::Document doc;
+        doc.SetObject();
+
+        JsonHelper::setMember(doc, DM_STATE_POWERED, state.power);
+
+        // Set other bulb properties only if the bulb is ON.
+        if (state.power == true)
+        {
+            JsonHelper::setMember(doc, DM_STATE_BRI, state.bri);
+            JsonHelper::setMember(doc, DM_STATE_HUE, state.hue);
+            JsonHelper::setMember(doc, DM_STATE_SAT, state.sat);
+
+
+            /* The light either considers the hue & saturation pair
+            or the xy pair. If both are present in the request, the "xy(csc)" array
+            is given priority and the Hue is sets itself to the color in "xy(csc)".
+
+            So, for this implementation of setState,
+            If the new "xy(csc)" value is NOT equal to the current "xy(csc)" value,
+            ONLY then is the "xy(csc)" set. The hue and sat from the previous state are
+            set above as they will be overriden by the "xy(csc)" anyway. */
+            if (fabs(state.csc[0] - m_state.csc[0]) > 0.0000005 &&
+                fabs(state.csc[1] - m_state.csc[1]) > 0.0000005)
+            {
+                rapidjson::Value cscArray(rapidjson::kArrayType);
+                cscArray.PushBack(state.csc[0], doc.GetAllocator());
+                cscArray.PushBack(state.csc[1], doc.GetAllocator());
+
+                JsonHelper::setMember(doc, DM_STATE_CSC, cscArray);
+            }
+        }
+
+
+        result = put(doc);
+    }
+    return result;
+}
+
+MPMResult HueLight::getConfig(light_config_t &config)
+{
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+
+    if (m_initialized)
+    {
+        /* this is a structure copy */
+        config = m_config;
+        result = MPM_RESULT_OK;
+    }
+    return result;
+}
+
+
+void HueLight::setConfig(light_config_t &config)
+{
+    /* this is a structure copy */
+    m_config = config;
+}
diff --git a/bridging/plugins/hue_plugin/hue_objects/hue_light.h b/bridging/plugins/hue_plugin/hue_objects/hue_light.h
new file mode 100644 (file)
index 0000000..78c451d
--- /dev/null
@@ -0,0 +1,240 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+
+/* This file contains the C++ representation definition of a Hue light */
+#ifndef __HUE_LIGHT_H__
+#define __HUE_LIGHT_H__
+
+#include <vector>
+#include <string>
+#include <stdio.h>
+#include <stdlib.h>
+#include <map>
+#include <memory>
+#include <typeinfo>
+#include "mpmErrorCode.h"
+#include "rapidjson.h"
+#include "document.h"
+#include "hue_defs.h"
+#include "messageHandler.h"
+
+
+/**
+ * The HueLight class represents one Hue Light instance. The class
+ * provides methods to get/set of the desired configuration of the light.
+ *
+ * NOTE: A configuration can be build up by calling the desired set* methods
+ *       followed by a call to put().
+ *
+ * For example;
+ *    setOn(true);
+ *    setHue(128);
+ *    setBrightness(131);
+ *    put();
+ *
+ * The representational state of the light is cached in the instance
+ * but can be refreshed by a call to get();
+ */
+class HueLight
+{
+    public:
+        typedef std::vector<std::shared_ptr<HueLight> > lights;
+
+        typedef struct light_state_tag
+        {
+            uint64_t hue;
+            uint64_t bri;
+            uint64_t sat;
+            /* CSC array. Will contain the x, y coordinates. Both will be in [0.0, 1.0]. */
+            double csc[2];
+            bool power;
+            std::string effect;
+            bool reachable;
+            std::string alert;
+            std::string colorMode;
+            uint16_t ct;
+
+            light_state_tag()
+            {
+                hue = bri = sat = ct = 0;
+                power = reachable = 0;
+                effect.empty();
+                alert.empty();
+                colorMode.empty();
+            }
+
+            bool operator!=(light_state_tag &state)
+            {
+                return !(*this == state);
+            }
+
+            bool operator==(light_state_tag &state)
+            {
+                /*we only care about following state changes*/
+                return state.hue == hue && state.bri == bri && state.sat == sat && state.power == power;
+            }
+        } light_state_t;
+
+        typedef struct light_config_tag
+        {
+            std::string type;
+            /** Light type       (Readonly) */
+            std::string name;
+            /** Friendly name               */
+            std::string modelId;
+            /** Model ID         (Readonly) */
+            std::string uniqueId;
+            /** Unique Lamp ID   (Readonly) */
+            std::string swversion;
+            /** Software version (Readonly) */
+            std::string uri; /*URI for this resource created using uniqueId*/
+        } light_config_t;
+
+
+        /**
+         * Constructor initializes a light instance
+         *
+         * @param[in] uri        is the uri for the light instance (e.g. <ip>/api/<user>/light/1)
+         * @param[in] json       is the initial JSON state for the  light. If empty,
+         *                       the constructor will attempt to get the state directly
+         *                       from the light.
+         * @param[in] bridge_ip  is the ip address of the hue bridge
+         * @param[in] bridge_mac is the mac address of the hue bridge
+         * @param[in] short_id   is the light id
+         */
+        HueLight();
+
+        HueLight(std::string uri, std::string bridge_ip, std::string bridge_mac, std::string short_id,
+                 std::string json);
+
+        virtual ~HueLight();
+
+        /**
+         * Retrieves the current light state of the Hue light.
+         *
+         * @param[in] state will hold the light state on success.
+         * @param[in] refresh indicates whether to return cached data or not.
+         *
+         * @return MPM_RESULT_OK on success, or another MPM_RESULT_XXX on error.
+         */
+        MPMResult getState(light_state_t &state, bool refresh = false);
+
+        /**
+         * Sets the current light state of the Hue light.
+         *
+         * @param[in] state is the desired state of the light.
+         *
+         * @return  MPM_RESULT_OK on success, or another MPM_RESULT_XXX on error.
+         */
+        MPMResult setState(light_state_t &state);
+
+        /**
+         * Retrieves the configuration information of the Hue light.
+         *
+         * @param[in,out] config will hold the configuraion data on success.
+         *
+         * @return MPM_RESULT_OK on success, or another MPM_RESULT_XXX on error.
+         */
+        MPMResult getConfig(light_config_t &config);
+
+
+        void setConfig(light_config_t &config);
+
+
+        std::string getBridgeMac()
+        {
+            return m_bridge_mac;
+        }
+
+        std::string getShortId()
+        {
+            return m_short_id;
+        }
+
+        std::string getUri()
+        {
+            return m_uri;
+        }
+
+    private:
+        /**
+         * Retrieves the current state of the light. Values read from
+         * are cached until a new get() is issued.
+         *
+         * @return MPM_RESULT_OK on success, or another MPM_RESULT_XXX code on error.
+         */
+        MPMResult get();
+
+        /**
+         * Sets the configured state of the light. Can be called for each setXXX() call
+         * or sent in bulk.
+         *
+         * @param[in] doc is a reference to the JSON object that holds the configuration to
+         *                send.
+         *
+         * @return MPM_RESULT_OK on success, or another MPM_RESULT_XXX code on error.
+         */
+        MPMResult put(rapidjson::Document &doc);
+
+        /**
+         * Retrieves the light state from the JSON representation
+         *
+         * @param[in,out] doc is a reference to the DOM that contains the JSON rep.
+         *
+         * @return MPM_RESULT_OK on success, or another MPM_RESULT_XXX on error.
+         */
+        MPMResult getInternalState(rapidjson::Document &doc);
+
+        /**
+         * Retrieves the configuration from the JSON representation
+         *
+         * @param[in,out] doc is a reference to the DOM that contains the JSON rep.
+         *
+         * @return MPM_RESULT_OK on success, or another MPM_RESULT_XXX on error.
+         */
+        MPMResult getInternalConfig(rapidjson::Document &doc);
+
+
+        MPMResult parseJsonResponse(std::string json);
+
+
+        /**
+         * Generates unique URI for this resource
+         */
+        std::string generateURI();
+
+        std::string m_uri;
+        std::string m_lastCurlResponse;
+        std::string m_user;
+        std::string m_bridge_ip;
+        std::string m_short_id;
+        std::string m_bridge_mac;
+
+        light_state_t m_state;
+        light_config_t m_config;
+        bool m_initialized;
+};
+
+typedef std::shared_ptr<HueLight> HueLightSharedPtr;
+
+
+#endif /* __HUE_LIGHT_H__ */
diff --git a/bridging/plugins/hue_plugin/hue_resource.cpp b/bridging/plugins/hue_plugin/hue_resource.cpp
new file mode 100644 (file)
index 0000000..d86febb
--- /dev/null
@@ -0,0 +1,1092 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+/* This file contains plugin specific code that adapts the native resource model
+ * of native devices into the resource model of OIC.  The file is divided into two
+ * sections; first plugin specific entry points are implemented followed by the
+ * implementation of the resource entity handler required by the IoTivity implementation
+ * for each resource.
+ *
+ * NOTE: This file is plumbed ready for dynamic resource additions.  There is a
+ * thread provided to manage the devices.  When a resource is found it is added
+ * to a work queue which is serviced by the plugin process function.  The plugin
+ * process function is a thread safe place for the plugin specific code to call
+ * OIC APIs.
+ */
+
+#include <algorithm>
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <string>
+#include <math.h>
+#include <signal.h>
+#include <pthread.h>
+#include <iostream>
+#include <map>
+#include <mutex>
+#include "logger.h"
+#include "mpmErrorCode.h"
+#include "pluginServer.h"
+#include "hue_light.h"
+#include "hue_auth_spec.h"
+#include "hue_light.h"
+#include "hue_file.h"
+#include "hue_bridge.h"
+#include "curlClient.h"
+#include "oic_string.h"
+#include "oic_malloc.h"
+#include "hue_resource.h"
+#include "iotivity_config.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include "messageHandler.h"
+#include "ConcurrentIotivityUtils.h"
+#include "IotivityWorkItem.h"
+#include "cbor.h"
+
+/*******************************************************************************
+ * Pound defines and structure declarations go here
+ ******************************************************************************/
+#define         MAX_QUERY_STRING                200
+#define         TAG                            "HUE_RESOURCE"
+
+using namespace OC::Bridging;
+
+/*******************************************************************************
+ * global data goes here
+ ******************************************************************************/
+MPMPluginCtx *g_pluginCtx = NULL;
+std::mutex addedLightsLock;
+std::mutex authorizedBridgesLock;
+
+std::map<std::string, HueBridge> authorizedBridges;
+typedef std::map<std::string, HueBridge>::iterator bridgeItr;
+
+std::map<std::string, HueLightSharedPtr> g_discoveredLightsMap;
+std::map<std::string, HueLightSharedPtr> addedLights;
+static void *hueDiscoveryThread(void *pointer);
+
+const std::string HUE_SWITCH_RESOURCE_TYPE = "oic.r.switch.binary";
+const std::string HUE_BRIGHTNESS_RESOURCE_TYPE = "oic.r.light.brightness";
+const std::string HUE_CHROMA_RESOURCE_TYPE = "oic.r.colour.chroma";
+const std::string SWITCH_RELATIVE_URI = "/switch";
+const std::string BRIGHTNESS_RELATIVE_URI = "/brightness";
+const std::string CHROMA_RELATIVE_URI = "/chroma";
+
+const uint BINARY_SWITCH_CALLBACK = 0;
+const uint BRIGHTNESS_CALLBACK = 1;
+const uint CHROMA_CALLBACK = 2;
+
+const static char CRED_FILE[] = "./oic_svr_db_hue.dat";
+
+FILE *hue_fopen(const char * , const char *mode)
+{
+    return fopen(CRED_FILE, mode);
+}
+
+MPMResult pluginCreate(MPMPluginCtx **pluginSpecificCtx)
+{
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+    if (g_pluginCtx == NULL)
+    {
+        *pluginSpecificCtx = NULL;
+
+        /* allocate a context structure for the plugin */
+        MPMPluginCtx *ctx = (MPMPluginCtx *) OICMalloc(sizeof(MPMPluginCtx));
+
+        /* initialize the plugin context */
+        if (ctx != NULL)
+        {
+            memset(ctx, 0, sizeof(MPMPluginCtx));
+            *pluginSpecificCtx = ctx;
+            g_pluginCtx = ctx;
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "Unable to allocate plugin specific context");
+            goto exit;
+        }
+
+        ctx->device_name = DEVICE_NAME;
+        ctx->resource_type = DEVICE_TYPE;
+        ctx->open = hue_fopen;
+
+        result = MPM_RESULT_OK;
+
+    }
+    else
+    {
+        result = MPM_RESULT_ALREADY_CREATED;
+    }
+exit:
+    OIC_LOG_V(INFO, TAG, "Plugin create return value:%d.", result);
+
+    /*
+     * NOTE: What do we do if the create for some reason failed.  To we assume that the destroy
+     * will be called if the create fails??  Let let the plugin loader pick up the pieces by
+     * calling destroy on an imperfectly created plugin.  Calling entry point APIs from within
+     * the implementation can cause some real problems (e.g. deadlock situations).
+     */
+
+    return result;
+}
+
+MPMResult pluginStart(MPMPluginCtx *ctx)
+{
+    MPMResult result = MPM_RESULT_STARTED_FAILED;
+    int error = 0;
+    if (ctx == NULL || g_pluginCtx == NULL)
+    {
+        goto exit;
+    }
+    if (ctx->started)
+    {
+        result = MPM_RESULT_ALREADY_STARTED;
+        goto exit;
+    }
+
+    result = hueInit(ctx, addAuthorizedBridgeCB, RemoveAuthorizedBridgeCB);
+    if (MPM_RESULT_OK == result)
+    {
+        /*start bridge discovery*/
+        if (DiscoverHueBridges() != MPM_RESULT_OK)
+        {
+            // DiscoverBridges if fails we try again in discovery thread, so don't return failure
+            OIC_LOG(ERROR, TAG, "DiscoverBridges failed");
+        }
+        else
+        {
+            OIC_LOG(INFO, TAG, " DiscoverBridges succeeded");
+        }
+        /* create house keeping thread */
+        ctx->stay_in_process_loop = true;
+
+        error = pthread_create(&(ctx->thread_handle), NULL,
+                               hueDiscoveryThread, ctx);
+        if (error == 0)
+        {
+            ctx->started = true;
+            result = MPM_RESULT_OK;
+        }
+        else
+        {
+            OIC_LOG_V(ERROR, TAG, "Can't create plugin specific thread :[%s]",
+                      strerror(errno));
+            pluginStop(ctx);
+            result = MPM_RESULT_STARTED_FAILED;
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "hueAuthCreate Failed. Cannot create plugin");
+    }
+exit:
+    OIC_LOG_V(INFO, TAG, "Plugin start return value:%d.", result);
+    return result;
+}
+
+// Checks if brightness has changed in the 0 - 100 range for OCF light.
+bool hasBrightnessChangedInOCFScale(const HueLight::light_state_t &stateprev,
+                                    const HueLight::light_state_t &statenew)
+{
+
+    uint16_t ocfBrightnessPrev = stateprev.bri / 2.54;
+    uint16_t ocfBrightnessNew = statenew.bri / 2.54;
+    return ocfBrightnessNew != ocfBrightnessPrev;
+}
+
+bool isSecureEnvSet()
+{
+    char *non_secure_env = getenv("NONSECURE");
+
+    if (non_secure_env != NULL && (strcmp(non_secure_env, "true")) == 0)
+    {
+        OIC_LOG(INFO, TAG, "Creating NON SECURE resources");
+        return false;
+    }
+    OIC_LOG(INFO, TAG, "Creating SECURE resources");
+    return true;
+}
+
+MPMResult createPayloadForMetaData(MPMResourceList **list, const std::string &configURI,
+                              const std::string rt, const std::string res_if)
+{
+    MPMResourceList *temp = (MPMResourceList *)OICCalloc(1, sizeof(MPMResourceList));
+    if (temp == NULL)
+    {
+        OIC_LOG_V(ERROR, TAG, "Calloc failed for createPayloadForMetaData %s", strerror(errno));
+        return MPM_RESULT_OUT_OF_MEMORY;
+    }
+
+    OICStrcpy(temp->rt, MPM_MAX_LENGTH_64, rt.c_str());
+    OICStrcpy(temp->href, MPM_MAX_URI_LEN, configURI.c_str());
+    OICStrcpy(temp->interfaces, MPM_MAX_LENGTH_64, res_if.c_str());
+    temp->bitmap = BM;
+
+    temp->next = *list;
+    *list = temp;
+    return MPM_RESULT_OK;
+}
+
+void addAuthorizedBridgeCB(const char *macAddress, const char *ClientId)
+{
+    HueBridge bridge; HueBridge::hue_bridge_data_tag bridgeData;
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+
+    if (authorizedBridges.find(macAddress) == authorizedBridges.end())
+    {
+        uint32_t prefix_size = MAX_QUERY_STRING;
+        char *prefix = (char *) OICMalloc(prefix_size);
+
+        /*get prefix for discovering lights*/
+        result = hueAuthGetHttpPrefix(prefix, &prefix_size, macAddress, ClientId);
+        if (result == MPM_RESULT_INSUFFICIENT_BUFFER)
+        {
+            prefix = (char *) realloc(prefix, prefix_size);
+            result = hueAuthGetHttpPrefix(prefix, &prefix_size, macAddress, ClientId);
+        }
+        if (result == MPM_RESULT_OK)
+        {
+            bridge.setBridgeCurlQuery(prefix);
+            bridge.getBridgeConfigFromCloud();
+            bridge.getBridgeConfig(bridgeData);
+            OIC_LOG_V(DEBUG, TAG,
+                      " \t\n\nBRIDGE AUTHORIZED\nclientID: %s\nip : %s\nmac: %s\nname : %s\nsw : %s\n", ClientId,
+                      bridgeData.ip.c_str(), bridgeData.mac.c_str(), bridgeData.name.c_str(),
+                      bridgeData.swVersion.c_str() );
+            OIC_LOG_V(INFO, TAG,  " \n Curl prefix for bridge is %s \n", prefix);
+        }
+        else
+        {
+            OIC_LOG_V(INFO, TAG,  " Failed To Authorize the bridge bridge - %s", macAddress);
+            OICFree(prefix);
+            return;
+        }
+
+        authorizedBridges[macAddress] = bridge;
+        OICFree(prefix);
+    }
+    else
+    {
+        OIC_LOG_V(INFO, TAG, "Bridge is already authorized \n");
+    }
+}
+
+MPMResult pluginScan(MPMPluginCtx *, MPMPipeMessage *)
+{
+    OIC_LOG(DEBUG, TAG,  "Inside Plugin  scan");
+    std::string uri, uniqueId ;
+    HueLight::light_config_t config;
+    HueLight::light_state_t state;
+
+    std::lock_guard<std::mutex> lock(authorizedBridgesLock);
+    /*iterate for every bridge in the authorized bridge map*/
+    for (bridgeItr it = authorizedBridges.begin(); it != authorizedBridges.end(); it++)
+    {
+        HueBridge *bridge = &(it->second);
+        if (bridge == NULL)
+        {
+            continue;
+        }
+        // now start a new discovery and get new lights
+
+        HueLight::lights lightsScanned;
+        bridge->discoverHueLights();
+        bridge->getScannedLights(lightsScanned);
+        for (uint32_t i = 0; i < lightsScanned.size(); ++i)
+        {
+            HueLightSharedPtr light = lightsScanned[i];
+            light->getConfig(config);
+            light->getState(state);
+
+            if (!state.reachable)
+            {
+                OIC_LOG(INFO, TAG, "Ignoring OFFLINE light");
+                continue;
+            }
+            uniqueId = createuniqueID(config.uniqueId);
+            uri = (HUE_LIGHT_URI + uniqueId) ;
+
+            OIC_LOG_V(INFO, TAG,
+                      "Found Reachable Light - light name=%s, id=%s, reachable=%d",
+                      config.name.c_str(), config.uniqueId.c_str(), state.reachable);
+
+            if (addedLights.find(uri) != addedLights.end())
+            {
+                OIC_LOG_V(INFO, TAG, "Already Added %s. Ignoring", uri.c_str());
+                continue;
+            }
+
+            g_discoveredLightsMap[uri] = light;
+
+            MPMSendResponse(uri.c_str(), uri.size(), MPM_SCAN);
+        }
+    }
+    return MPM_RESULT_OK;
+}
+
+/**
+ *  CreateuniqueID - Creates the unique id by removing Delimiters..
+ *  @param[in] deviceId - Unique Id of the Device
+ *  @return unique id without any delimiters
+ */
+std::string createuniqueID(std::string deviceId)
+{
+    std::string uniqueId(deviceId);
+    std::string token = "";
+    std::string delimiter1 = ":";
+    std::string delimiter2 = "-";
+    size_t pos = 0;
+
+    while ( (pos = uniqueId.find(delimiter1)) != std::string::npos)
+    {
+        uniqueId.replace(pos, 1, token);
+    }
+    while ( (pos = uniqueId.find(delimiter2)) != std::string::npos)
+    {
+        uniqueId.replace(pos, 3, token);
+    }
+    return uniqueId;
+}
+
+void createOCFResources(std::string uri)
+{
+    uint8_t resourceProperties = (OC_OBSERVABLE | OC_DISCOVERABLE);
+    if (isSecureEnvSet())
+    {
+        resourceProperties |= OC_SECURE;
+    }
+
+    ConcurrentIotivityUtils::queueCreateResource(uri + SWITCH_RELATIVE_URI,
+                    HUE_SWITCH_RESOURCE_TYPE.c_str(), OC_RSRVD_INTERFACE_ACTUATOR,
+                    entityHandler, (void *) BINARY_SWITCH_CALLBACK, resourceProperties);
+
+    ConcurrentIotivityUtils::queueCreateResource(uri + BRIGHTNESS_RELATIVE_URI,
+             HUE_BRIGHTNESS_RESOURCE_TYPE.c_str(), OC_RSRVD_INTERFACE_ACTUATOR,
+             entityHandler, (void *) BRIGHTNESS_CALLBACK, resourceProperties);
+
+
+    ConcurrentIotivityUtils::queueCreateResource(uri + CHROMA_RELATIVE_URI,
+            HUE_CHROMA_RESOURCE_TYPE.c_str(), OC_RSRVD_INTERFACE_ACTUATOR,
+            entityHandler, (void *) CHROMA_CALLBACK, resourceProperties);
+}
+
+MPMResult pluginAdd(MPMPluginCtx *, MPMPipeMessage *message)
+{
+    if (message->payloadSize <= 0 && message->payload == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "No payload received, failed to add device");
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+
+    MPMResourceList *list  = NULL;
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+
+    std::string uri = reinterpret_cast<const char *>(message->payload);
+
+    if (addedLights.find(uri) != addedLights.end())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s already added", uri.c_str());
+        return MPM_RESULT_ALREADY_CREATED;
+    }
+    if (g_discoveredLightsMap.find(uri) == g_discoveredLightsMap.end())
+    {
+        OIC_LOG_V(ERROR, TAG, "%s was NOT discovered in a scan", uri.c_str());
+        return result;
+    }
+
+    std::lock_guard<std::mutex> lock(addedLightsLock);
+    addedLights[uri] = g_discoveredLightsMap[uri];
+
+    uint8_t *buff = (uint8_t *)OICCalloc(1, MPM_MAX_METADATA_LEN);
+    if (buff == NULL)
+    {
+        OIC_LOG_V(ERROR, TAG, "Calloc failed %s", strerror(errno));
+        return MPM_RESULT_OUT_OF_MEMORY;
+    }
+    size_t size = MPM_MAX_METADATA_LEN;
+    HueLightSharedPtr light; hueFile bridgeCtx;
+    hueLightDetails deviceDetails;
+    HueLight::light_config_t config;
+    MPMDeviceSpecificData deviceConfiguration;
+    memset(&deviceDetails, 0, sizeof(hueLightDetails));
+    memset(&deviceConfiguration, 0, sizeof(MPMDeviceSpecificData));
+
+    // Create Resources and form metadata for RECONNECT
+
+    createOCFResources(uri);
+
+    result = createPayloadForMetaData(&list, uri+SWITCH_RELATIVE_URI,
+                HUE_SWITCH_RESOURCE_TYPE.c_str(), OC_RSRVD_INTERFACE_ACTUATOR);
+
+    result= createPayloadForMetaData(&list, uri + BRIGHTNESS_RELATIVE_URI,
+                HUE_BRIGHTNESS_RESOURCE_TYPE.c_str(),OC_RSRVD_INTERFACE_ACTUATOR);
+
+    result = createPayloadForMetaData(&list, uri + CHROMA_RELATIVE_URI,
+                HUE_CHROMA_RESOURCE_TYPE.c_str(), OC_RSRVD_INTERFACE_ACTUATOR);
+
+    if(result != MPM_RESULT_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, " Failed creating payload for metadata");
+        return result;
+    }
+
+    light = g_discoveredLightsMap[uri];
+    light->getConfig(config);
+
+    std::string data;
+    data =  light->getBridgeMac();
+    std::transform(data.begin(), data.end(), data.begin(), ::tolower);
+    OICStrcpy(deviceDetails.bridgeMac, MPM_MAX_UNIQUE_ID_LEN, data.c_str());
+    deviceDetails.bridgeMac[MPM_MAX_UNIQUE_ID_LEN - 1] = '\0';
+
+    OICStrcpy(deviceDetails.lightMac, MPM_MAX_LENGTH_32, config.uniqueId.c_str());
+    OICStrcpy(deviceDetails.lightUri, MPM_MAX_URI_LEN, config.uri.c_str());
+    OICStrcpy(deviceDetails.prefix, MPM_MAX_LENGTH_256, light->getUri().c_str());
+    OICStrcpy(deviceDetails.lightNo, MPM_MAX_LENGTH_32, light->getShortId().c_str());
+
+    findAuthorizedBridge(deviceDetails.bridgeMac, NULL, bridgeCtx);
+    OICStrcpy(deviceDetails.clientId, MPM_MAX_LENGTH_64, bridgeCtx.clientID);
+
+
+    OICStrcpy(deviceConfiguration.devName, MPM_MAX_LENGTH_64, DEVICE_NAME);
+    OICStrcpy(deviceConfiguration.devType, MPM_MAX_LENGTH_64, DEVICE_TYPE);
+    OICStrcpy(deviceConfiguration.manufacturerName, MPM_MAX_LENGTH_256, MANUFACTURER_NAME);
+    MPMFormMetaData(list, &deviceConfiguration, buff, size, &deviceDetails, sizeof(deviceDetails));
+
+    MPMAddResponse response;
+    memset(&response, 0, sizeof(MPMAddResponse));
+    OICStrcpy(response.uri, MPM_MAX_URI_LEN, uri.c_str());
+    memcpy(response.metadata, buff, MPM_MAX_METADATA_LEN);
+    size_t response_size = sizeof(MPMAddResponse);
+
+    MPMSendResponse(&response, response_size, MPM_ADD);
+
+    OICFree(buff);
+
+    return MPM_RESULT_OK;
+}
+
+MPMResult pluginRemove(MPMPluginCtx *, MPMPipeMessage *message)
+{
+    if (message->payloadSize <= 0 && message->payload == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "No paylaod received, failed to remove device");
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+
+    std::string uri = reinterpret_cast<const char*>(message->payload);
+    OIC_LOG_V(DEBUG, TAG, "device uri to be removed - %s ", uri.c_str());
+
+    std::lock_guard<std::mutex> lock(addedLightsLock);
+    if (addedLights.find(uri) == addedLights.end())
+    {
+        OIC_LOG(ERROR, TAG, "Device to be removed is not added yet");
+        return MPM_RESULT_NOT_PRESENT;
+    }
+
+    ConcurrentIotivityUtils::queueDeleteResource(uri + SWITCH_RELATIVE_URI);
+    ConcurrentIotivityUtils::queueDeleteResource(uri + BRIGHTNESS_RELATIVE_URI);
+    ConcurrentIotivityUtils::queueDeleteResource(uri + CHROMA_RELATIVE_URI);
+
+    addedLights.erase(uri);
+
+    MPMSendResponse(uri.c_str(), uri.size(), MPM_REMOVE);
+
+    return MPM_RESULT_OK;
+}
+
+MPMResult pluginReconnect(MPMPluginCtx *, MPMPipeMessage *message)
+{
+    if (message->payloadSize <= 0 && message->payload == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "No paylaod received, failed to reconnect");
+        return MPM_RESULT_INTERNAL_ERROR;
+    }
+
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+    hueLightDetails *plugindetails = NULL;
+    void *details = NULL;
+    HueDiscoveredCtx discoveredCtx;
+    std::size_t pos = 0;
+    std::string light_Prefix, ip, light_mac, light_no, uri;
+    HueBridge bridge;
+    MPMResourceList *list = NULL, *temp = NULL;
+
+    MPMParseMetaData(message->payload, MPM_MAX_METADATA_LEN, &list, &details);
+    plugindetails = (hueLightDetails *) details;
+
+    // Find Bridge ip and light id;
+    light_no = plugindetails->lightNo;
+    light_Prefix = plugindetails->prefix;
+    pos = light_Prefix.find("/");
+    ip = light_Prefix.substr(0, (pos));
+
+    OIC_LOG_V(DEBUG, TAG,
+              " \n\n Reconnect meta data \n\n Bridge Mac - %s\n Light Mac - %s\nip - %s\n Client ID -%s\n Light no - %s\n"
+              "\n prefix - %s \n ", plugindetails->bridgeMac, plugindetails->lightMac, ip.c_str(),
+              plugindetails->clientId,
+              plugindetails->lightNo, plugindetails->prefix);
+
+    if ((plugindetails->bridgeMac != NULL) && ( plugindetails->clientId != NULL))
+    {
+        if (authorizedBridges.find(plugindetails->bridgeMac) == authorizedBridges.end())
+        {
+            memset(&discoveredCtx, 0, sizeof(HueDiscoveredCtx));
+            if (false == findDiscoveredBridge(plugindetails->bridgeMac, &discoveredCtx))
+            {
+                OICStrcpy(discoveredCtx.macAddrString, MAX_STRING - 1, plugindetails->bridgeMac);
+                OICStrcpy(discoveredCtx.ipAddrString, MAX_STRING - 1, ip.c_str());
+                OICStrcpy(discoveredCtx.clientIDs, MAX_STRING * MAX_CLIENTS, plugindetails->clientId);
+                discoveredCtx.numClients = 1;
+                addAuthorizedBridge(plugindetails->bridgeMac, plugindetails->clientId);
+                result = addDiscoveredBridge(discoveredCtx);
+            }
+            else
+            {
+                updateDiscoverBridgeDetails(plugindetails->bridgeMac, plugindetails->clientId);
+            }
+            uint32_t prefix_size = MAX_QUERY_STRING;
+            char *prefix = (char *) OICMalloc(prefix_size);
+            result = hueAuthGetHttpPrefix(prefix, &prefix_size, plugindetails->bridgeMac,
+                                          plugindetails->clientId);
+            if (result == MPM_RESULT_INSUFFICIENT_BUFFER)
+            {
+                prefix = (char *) realloc(prefix, prefix_size);
+                result = hueAuthGetHttpPrefix(prefix, &prefix_size, plugindetails->bridgeMac,
+                                              plugindetails->clientId);
+            }
+            if (result != MPM_RESULT_OK)
+            {
+                OIC_LOG(DEBUG, TAG, "hueAuthGetHttpPrefix failed");
+                OICFree(prefix);
+                return result;
+            }
+            bridge.setBridgeMAC(plugindetails->bridgeMac);
+            bridge.setBridgeCurlQuery(prefix);
+            authorizedBridges[plugindetails->bridgeMac] = bridge;
+            OICFree(prefix);
+        }
+    }
+    for (bridgeItr it = authorizedBridges.begin(); it != authorizedBridges.end(); it++)
+    {
+        HueBridge *authorizedbridge = &(it->second);
+        std::string data;
+        data =  authorizedbridge->getBridgeMAC();
+        std::transform(data.begin(), data.end(), data.begin(), ::tolower);
+        if (plugindetails->bridgeMac == data)
+        {
+            OIC_LOG(DEBUG, TAG, "Bridge Found and is authorized");
+            addReconnectLightsToBridge(plugindetails, authorizedbridge, ip);
+            result = MPM_RESULT_OK;
+        }
+    }
+
+    while (list)
+    {
+        temp = list;
+        list = list->next;
+        OICFree(temp);
+    }
+    free(plugindetails);
+    return MPM_RESULT_OK;
+}
+
+void addReconnectLightsToBridge(hueLightDetails *plugindetails, HueBridge *bridge,
+                                std::string bridgeIp)
+{
+    HueLight::light_config_t config;
+    std::string uuid, uri;
+    OIC_LOG(INFO, TAG, " RECONNECTING ALL THE LIGHTS.......");
+    std::shared_ptr<HueLight> light = std::make_shared<HueLight>(plugindetails->prefix, bridgeIp,
+                                      plugindetails->bridgeMac, plugindetails->lightNo, "NULL");
+    if (!light)
+    {
+        OIC_LOG(ERROR, TAG, " Pointer returned NULL to the light object");
+        return;
+    }
+    config.uri = plugindetails->lightUri;
+    config.uniqueId = plugindetails->lightMac;
+    light->setConfig(config);
+    bridge->fillLightDetails(light);
+
+    uuid = createuniqueID(config.uniqueId);
+    uri = (HUE_LIGHT_URI + uuid );
+    createOCFResources(uri);
+
+    g_discoveredLightsMap[uri] = light;
+    addedLights[uri] = light;
+}
+
+/*
+ * Removes bridge from the authorized bridge map.
+ */
+void RemoveAuthorizedBridgeCB(const char *macAddrString)
+{
+    OIC_LOG_V(INFO, TAG, "Remove Bridge called for bridge = %s", macAddrString);
+    std::lock_guard<std::mutex> lock(authorizedBridgesLock);
+    bridgeItr it = authorizedBridges.find(macAddrString);
+    if (it != authorizedBridges.end())
+    {
+        /*remove the bridge*/
+        authorizedBridges.erase(it);
+    }
+    return;
+}
+
+
+/*  Plugin specific entry-point function to stop the plugin's threads
+ *
+ * returns:
+ *     MPM_RESULT_OK             - no errors
+ *     MPM_RESULT_INTERNAL_ERROR - stack process error
+ */
+MPMResult pluginStop(MPMPluginCtx *ctx)
+{
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+
+    if (NULL != ctx && g_pluginCtx != NULL)
+    {
+        result = MPM_RESULT_OK;
+        //stop the presence before stopping the plugin
+        OCStopPresence();
+
+        if (ctx->started == true)
+        {
+            ctx->stay_in_process_loop = false;
+            pthread_join(ctx->thread_handle, NULL);
+            ctx->started = false;
+        }
+
+        //destroy the resources
+        hueAuthDestroy();
+        clearBridgeDetails();
+    }
+    OIC_LOG_V(INFO, TAG, "Plugin stop: OUT - return value:%d", result);
+
+    return (result);
+}
+
+MPMResult pluginDestroy(MPMPluginCtx *ctx)
+{
+    MPMResult result = MPM_RESULT_INTERNAL_ERROR;
+
+    if (ctx != NULL && g_pluginCtx != NULL)
+    {
+        result = MPM_RESULT_OK;
+        if (ctx->started == true)
+        {
+            result = pluginStop(ctx);
+        }
+
+        /* freeing the resource allocated in create */
+        OICFree(ctx);
+        g_pluginCtx = NULL;
+    }
+
+    OIC_LOG_V(INFO, TAG, "Plugin destroy's return value:%d", result);
+
+    return (result);
+}
+
+OCEntityHandlerResult handleEntityHandlerRequests(
+    OCEntityHandlerFlag ,
+    OCEntityHandlerRequest *entityHandlerRequest,
+    std::string resourceType)
+{
+    OCEntityHandlerResult ehResult = OC_EH_ERROR;
+    OCRepPayload *responsePayload = NULL;
+    OCRepPayload *payload = OCRepPayloadCreate();
+
+    try
+    {
+        if ((entityHandlerRequest == NULL))
+        {
+            throw "Entity handler received a null entity request context" ;
+        }
+
+        std::string uri = OCGetResourceUri(entityHandlerRequest->resource);
+        HueLightSharedPtr hueLight = getHueLightFromOCFResourceUri(uri);
+        char *interfaceQuery = NULL;
+        char *resourceTypeQuery = NULL;
+        char *dupQuery = OICStrdup(entityHandlerRequest->query);
+        if (dupQuery)
+        {
+            MPMExtractFiltersFromQuery(dupQuery, &interfaceQuery, &resourceTypeQuery);
+        }
+
+        switch (entityHandlerRequest->method)
+        {
+            case OC_REST_GET:
+                OIC_LOG_V(INFO, TAG, " GET Request for: %s", uri.c_str());
+                ehResult = processGetRequest(payload, hueLight, resourceType);
+                break;
+
+            case OC_REST_PUT:
+            case OC_REST_POST:
+
+                OIC_LOG_V(INFO, TAG, "PUT / POST Request on %s", uri.c_str());
+                ehResult = processPutRequest(entityHandlerRequest, hueLight, resourceType, payload);
+
+                //  To include "if" in all payloads.
+                interfaceQuery = (char *) OC_RSRVD_INTERFACE_DEFAULT;
+                break;
+
+            default:
+                OIC_LOG_V(ERROR, TAG, "UnSupported Method [%d] Received ", entityHandlerRequest->method);
+                ConcurrentIotivityUtils::respondToRequestWithError(entityHandlerRequest, " Unsupported Method",
+                        OC_EH_METHOD_NOT_ALLOWED);
+                 return OC_EH_OK;
+        }
+        responsePayload = getCommonPayload(uri.c_str(),interfaceQuery, resourceType, payload);
+        ConcurrentIotivityUtils::respondToRequest(entityHandlerRequest, responsePayload, ehResult);
+        OICFree(dupQuery);
+    }
+    catch (const char *errorMessage)
+    {
+        OIC_LOG_V(ERROR, TAG, "Error - %s ", errorMessage);
+        ConcurrentIotivityUtils::respondToRequestWithError(entityHandlerRequest, errorMessage, OC_EH_ERROR);
+        ehResult = OC_EH_OK;
+    }
+
+    OCRepPayloadDestroy(responsePayload);
+    return ehResult;
+}
+
+// Entity handler for binary switch
+OCEntityHandlerResult entityHandler(OCEntityHandlerFlag flag,
+            OCEntityHandlerRequest *entityHandlerRequest, void *callback)
+{
+    uintptr_t callbackParamResourceType = (uintptr_t)callback;
+    std::string resourceType;
+
+    if (callbackParamResourceType == BINARY_SWITCH_CALLBACK)
+    {
+        resourceType = HUE_SWITCH_RESOURCE_TYPE;
+    }
+    else if (callbackParamResourceType == BRIGHTNESS_CALLBACK)
+    {
+        resourceType = HUE_BRIGHTNESS_RESOURCE_TYPE;
+    }
+    else
+    {
+        resourceType = HUE_CHROMA_RESOURCE_TYPE;
+    }
+    return handleEntityHandlerRequests(flag, entityHandlerRequest, resourceType);
+}
+
+OCEntityHandlerResult processGetRequest(OCRepPayload *payload, HueLightSharedPtr hueLight,
+                                        std::string resType)
+{
+    HueLight::light_state_t light_state;
+    hueLight->getState(light_state);
+
+    if (payload == NULL)
+    {
+        throw "payload is null";
+    }
+
+    if (HUE_SWITCH_RESOURCE_TYPE == resType)
+    {
+        if (!OCRepPayloadSetPropBool(payload, "value", light_state.power))
+        {
+            throw "Failed to set 'value' (power) in payload";
+        }
+        OIC_LOG_V(INFO, TAG, "Light State: %s", light_state.power ? "true" : "false");
+    }
+    else if (HUE_BRIGHTNESS_RESOURCE_TYPE == resType)
+    {
+        uint8_t ocfBrightness = light_state.bri / 2.54;
+
+        if (!OCRepPayloadSetPropInt(payload, "brightness", ocfBrightness))
+        {
+            throw "Failed to set 'brightness' in payload";
+        }
+        OIC_LOG_V(INFO, TAG, " Brightness State (Hue Bulb): %ld  Brightness(OCF) : %d",
+                              light_state.bri, ocfBrightness);
+    }
+    else if (HUE_CHROMA_RESOURCE_TYPE == resType)
+    {
+        if (!OCRepPayloadSetPropInt(payload, "hue", light_state.hue) ||
+            !OCRepPayloadSetPropInt(payload, "saturation", light_state.sat))
+        {
+            throw "Failed to set 'hue' or 'saturation' in payload" ;
+        }
+        size_t csc_dimensions[MAX_REP_ARRAY_DEPTH] = {2, 0, 0};
+        if (!OCRepPayloadSetDoubleArray(payload, "csc", light_state.csc, csc_dimensions))
+        {
+            throw  "Failed to set csc in payload" ;
+        }
+        OIC_LOG_V(INFO, TAG, "hue: %ld, sat: %ld, csc: [%f, %f] in payload.",
+                  light_state.hue,
+                  light_state.sat,
+                  light_state.csc[0],
+                  light_state.csc[1]);
+    }
+    else
+    {
+        throw "Failed due to unkwown resource type";
+    }
+    return OC_EH_OK;
+}
+
+OCEntityHandlerResult processPutRequest(OCEntityHandlerRequest *ehRequest,
+                                        HueLightSharedPtr hueLight, std::string resourceType,
+                                        OCRepPayload *payload)
+{
+
+    if (!ehRequest || !ehRequest->payload ||
+                                    ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
+    {
+        throw "Incoming payload is NULL or not a representation";
+    }
+
+    OCRepPayload *input = reinterpret_cast<OCRepPayload *>(ehRequest->payload);
+    if (!input)
+    {
+        throw "PUT payload is null";
+    }
+    HueLight::light_state_t state;
+    light_resource_t light_resource;
+    if (hueLight->getState(state, true) != MPM_RESULT_OK)
+    {
+        throw "Error Getting light. Aborting PUT" ;
+    }
+
+    if (HUE_SWITCH_RESOURCE_TYPE ==  resourceType)
+    {
+        if (!OCRepPayloadGetPropBool(input, "value", &light_resource.power))
+        {
+            throw "No value (power) in representation" ;
+        }
+        OIC_LOG_V(INFO, TAG, "PUT/POST value (power):%s", light_resource.power ? "true" : "false");
+        state.power = light_resource.power;
+        if (!OCRepPayloadSetPropBool(payload, "value", state.power))
+        {
+            throw "Failed to set 'value' (power) in payload";
+        }
+    }
+    else if (HUE_BRIGHTNESS_RESOURCE_TYPE == resourceType)
+    {
+        if (!OCRepPayloadGetPropInt(input, "brightness", &light_resource.bri))
+        {
+            throw "No brightness in representation" ;
+        }
+        OIC_LOG_V(INFO, TAG, "PUT/POST brightness:%ld", light_resource.bri);
+
+        // Sclae up from 1-100 for OCF Light to 1-254 for Hue device
+        light_resource.bri *= 2.54;
+
+        // Add 1 to make sure when we scale down later by dividing by 2.54, we try and
+        // arryto the same number.
+        if (light_resource.bri != 254)
+        {
+            light_resource.bri += 1;
+        }
+        // Get the current powered state of light and then set the value accordingly.
+        // If the light is turned off, then PUT to bri will yield in a blink
+        // and quickly to off state. In short, it is invalid.
+        state.bri = light_resource.bri;
+        state.power = true;
+
+        if (!OCRepPayloadSetPropInt(payload, "brightness", state.bri))
+        {
+            throw "Failed to set 'brightness' in payload";
+        }
+    }
+    else if (HUE_CHROMA_RESOURCE_TYPE == resourceType)
+    {
+        bool isChromaPropertyInPayload = false;
+
+        if (!OCRepPayloadGetPropInt(input, "hue", &light_resource.hue))
+        {
+            isChromaPropertyInPayload = true;
+            OIC_LOG(INFO, TAG, "No hue in PUT payload");
+        }
+        else
+        {
+            state.hue = light_resource.hue;
+            isChromaPropertyInPayload = true;
+            OIC_LOG_V(INFO, TAG, "PUT/POST hue :%ld", state.hue);
+        }
+
+        if (!OCRepPayloadGetPropInt(input, "saturation", &light_resource.sat))
+        {
+            throw "No saturation in PUT payload";
+        }
+        else
+        {
+            state.sat = light_resource.sat;
+            isChromaPropertyInPayload = true;
+            OIC_LOG_V(INFO, TAG, "PUT/POST sat :%ld", state.sat);
+        }
+
+        if (!OCRepPayloadSetPropInt(payload, "hue", state.hue) ||
+            !OCRepPayloadSetPropInt(payload, "saturation", state.sat))
+        {
+            throw "Failed to set 'hue' or 'saturation' in payload" ;
+        }
+
+        size_t csc_dimensions[MAX_REP_ARRAY_DEPTH] = {2, 0, 0};
+        double *cscInPayload = NULL;
+        if (!OCRepPayloadGetDoubleArray(input, "csc", &cscInPayload, csc_dimensions))
+        {
+            OIC_LOG(INFO, TAG, "No csc in PUT payload");
+        }
+        else
+        {
+            if (cscInPayload != NULL)
+            {
+                isChromaPropertyInPayload = true;
+                state.csc[0] = cscInPayload[0];
+                state.csc[1] = cscInPayload[1];
+                OIC_LOG_V(INFO, TAG, "PUT/POST csc (sat) :[%f, %f]", state.csc[0], state.csc[1]);
+            }
+        }
+
+        if (isChromaPropertyInPayload)
+        {
+            state.power = true;
+            light_resource.power = true;
+        }
+        OICFree(cscInPayload);
+    }
+    else
+    {
+        throw "Failed due to unkwown resource type" ;
+    }
+
+    if (hueLight->setState(state) != MPM_RESULT_OK)
+    {
+        throw "Error setting light state" ;
+    }
+    return OC_EH_OK;
+}
+
+OCRepPayload *getCommonPayload(const char *uri, char *interfaceQuery,
+                               std::string resType, OCRepPayload *payload)
+{
+    if (!OCRepPayloadSetUri(payload, uri))
+    {
+        throw "Unable to set URI in the payload";
+    }
+
+    if (!OCRepPayloadAddResourceType(payload, resType.c_str()))
+    {
+        throw "Failed to set light resource type" ;
+    }
+    OIC_LOG_V(INFO, TAG, "Checking against if: %s", interfaceQuery);
+
+    // If the interface filter is explicitly oic.if.baseline, include all properties.
+    if (interfaceQuery && std::string(interfaceQuery) == std::string(OC_RSRVD_INTERFACE_DEFAULT))
+    {
+        if (!OCRepPayloadAddInterface(payload, OC_RSRVD_INTERFACE_ACTUATOR))
+        {
+            throw "Failed to set light interface";
+        }
+
+        if (!OCRepPayloadAddInterface(payload, std::string(OC_RSRVD_INTERFACE_DEFAULT).c_str()))
+        {
+            throw "Failed to set baseline interface" ;
+        }
+    }
+    return payload;
+}
+
+/**
+ * Monitors the light state changes and sends notification if
+ * any change. Also discovers new Bridges...!
+ *
+ * @param[in] pointer pluginctx
+ */
+static void *hueDiscoveryThread(void *pointer)
+{
+    MPMPluginCtx *ctx = (MPMPluginCtx *) pointer;
+    if (ctx == NULL)
+    {
+        return NULL;
+    }
+    OIC_LOG(INFO, TAG, "Plugin specific thread handler entered");
+    HueLight::light_config_t config;
+    std::string uniqueId, uri;
+
+    while (true == ctx->stay_in_process_loop)
+    {
+        addedLightsLock.lock();
+        for (auto itr : addedLights)
+        {
+            HueLightSharedPtr light = itr.second;
+            if (!light)
+            {
+                continue;
+            }
+            light->getConfig(config);
+
+            std::string uniqueId = createuniqueID(config.uniqueId);
+            uri = (HUE_LIGHT_URI + uniqueId ) ;
+
+            HueLight::light_state_t oldState, newState ;
+            light->getState(oldState);
+            light->getState(newState, true);
+
+            if (oldState.power != newState.power)
+            {
+                ConcurrentIotivityUtils::queueNotifyObservers(itr.first + SWITCH_RELATIVE_URI);
+            }
+            else if (hasBrightnessChangedInOCFScale(oldState, newState))
+            {
+                ConcurrentIotivityUtils::queueNotifyObservers(itr.first + BRIGHTNESS_RELATIVE_URI);
+            }
+            else if ((oldState.hue != newState.hue) || (oldState.sat != newState.sat))
+            {
+                ConcurrentIotivityUtils::queueNotifyObservers(itr.first + CHROMA_RELATIVE_URI);
+            }
+            else
+            {
+                ; //Do nothing here..
+            }
+        }
+        addedLightsLock.unlock();
+        /*start the periodic bridge discovery*/
+        DiscoverHueBridges();
+        sleep(MPM_THREAD_PROCESS_SLEEPTIME);
+    }
+    OIC_LOG(INFO, TAG, "Leaving plugin specific thread handler");
+    pthread_exit(NULL);
+}
+
+HueLightSharedPtr getHueLightFromOCFResourceUri(std::string resourceUri)
+{
+    OIC_LOG_V(INFO, TAG, "Request for %s ", resourceUri.c_str());
+
+    for (auto uriToHuePair : addedLights)
+    {
+        if (resourceUri.find(uriToHuePair.first) != std::string::npos)
+        {
+            return uriToHuePair.second;
+        }
+    }
+    throw "Resource" + resourceUri + "not found";
+}
diff --git a/bridging/plugins/hue_plugin/hue_resource.h b/bridging/plugins/hue_plugin/hue_resource.h
new file mode 100644 (file)
index 0000000..ff4661f
--- /dev/null
@@ -0,0 +1,101 @@
+//******************************************************************
+//
+// Copyright 2017 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+
+
+#include "mpmErrorCode.h"
+#include <string.h>
+#include <memory>
+#include "ocstack.h"
+#include "octypes.h"
+#include "ocpayload.h"
+#include "hue_light.h"
+#include "hue_bridge.h"
+#include "messageHandler.h"
+#ifndef __HUE_RESOURCE_H__
+#define __HUE_RESOURCE_H__
+
+#define DEVICE_NAME          "Philips Hue Translator"
+#define DEVICE_TYPE          "oic.d.light"
+#define MANUFACTURER_NAME    "Philips"
+#define MAX_RESOURCES        3
+#define BM                   3
+#define HUE_LIGHT_URI        "/hue/"
+
+// Structure used in Put_request to get the appropriate attribute Values
+typedef struct light_resource_t
+{
+    bool power;
+    int64_t bri;
+    int64_t hue;
+    int64_t sat;
+    double csc[2];
+} light_resource;
+
+typedef struct
+{
+    char prefix[MPM_MAX_LENGTH_256];
+    char lightNo[MPM_MAX_LENGTH_32];
+    char bridgeMac[MPM_MAX_UNIQUE_ID_LEN];
+    char lightMac[MPM_MAX_LENGTH_32];
+    char lightUri[MPM_MAX_URI_LEN];
+    char clientId[MPM_MAX_LENGTH_64];
+    light_resource resource_state;
+} hueLightDetails;
+
+/*******************************************************************************
+ * prototypes go here
+ ******************************************************************************/
+OCEntityHandlerResult handleEntityHandlerRequests(OCEntityHandlerFlag flag,
+        OCEntityHandlerRequest *entityHandlerRequest,
+        std::string resourceType);
+
+OCEntityHandlerResult entityHandler(OCEntityHandlerFlag flag,
+    OCEntityHandlerRequest *entityHandlerRequest, void *callback);
+
+OCEntityHandlerResult processPutRequest(OCEntityHandlerRequest *ehRequest,
+    HueLightSharedPtr hueLight, std::string resType, OCRepPayload *payload);
+
+OCEntityHandlerResult processGetRequest(OCRepPayload *payload, HueLightSharedPtr hueLight,
+                                        std::string resType);
+
+OCRepPayload *getCommonPayload(const char *uri, char *interfaceQuery,
+                               std::string resType, OCRepPayload *payload);
+
+
+/**
+ * Callback is called when a bridge is authorized. It adds the bridge
+ * in bridge map and inits some bridge data.
+ *
+ * @param[in] macAddress Mac id of the bridge
+ * @param[in] clientID        Clientid of the bridge
+ */
+void addAuthorizedBridgeCB(const char *macAddrString, const char *ClientId);
+
+void RemoveAuthorizedBridgeCB(const char *macAddrString);
+
+HueLightSharedPtr getHueLightFromOCFResourceUri(std::string resourceUri);
+
+void addReconnectLightsToBridge(hueLightDetails *plugindetails, HueBridge *bridge,
+                                std::string bridgeIp);
+
+std::string createuniqueID(std::string deviceID);
+
+#endif /*__HUE_RESOURCE_H__*/