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'))
--- /dev/null
+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.
--- /dev/null
+#******************************************************************
+#
+# 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')
+
+
--- /dev/null
+[{
+ "id": "001788fffe168fe7",
+ "username": "newdeveloper"
+}]
--- /dev/null
+//******************************************************************
+//
+// 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);
+}
--- /dev/null
+//******************************************************************
+//
+// 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__ */
--- /dev/null
+//******************************************************************
+//
+// 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();
+}
+
--- /dev/null
+//******************************************************************
+//
+// 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__ */
--- /dev/null
+//******************************************************************
+//
+// 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);
+}
--- /dev/null
+//******************************************************************
+//
+// 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__ */
--- /dev/null
+//******************************************************************
+//
+// 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__ */
--- /dev/null
+//******************************************************************
+//
+// 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;
+}
--- /dev/null
+//******************************************************************
+//
+// 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__ */
--- /dev/null
+//******************************************************************
+//
+// 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";
+}
--- /dev/null
+//******************************************************************
+//
+// 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__*/