diff --git a/include/hueplusplus/Bridge.h b/include/hueplusplus/Bridge.h index e754fbf..e208f3e 100644 --- a/include/hueplusplus/Bridge.h +++ b/include/hueplusplus/Bridge.h @@ -99,6 +99,12 @@ public: //! \param username Username that is used to control the Hue bridge void AddUsername(const std::string& mac, const std::string& username); + //! \brief Function that adds a client key to the clientkeys map + //! + //! \param mac MAC address of Hue bridge + //! \param clientkey Client key that is used to control the Hue bridge in entertainment mode + void AddClientKey(const std::string& mac, const std::string& clientkey); + //! \brief Function that returns a map of mac addresses and usernames. //! //! Note these should be saved at the end and re-loaded with \ref AddUsername @@ -120,6 +126,8 @@ private: std::map usernames; //!< Maps all macs to usernames added by \ref //!< BridgeFinder::AddUsername + std::map clientkeys; //!< Maps all macs to clientkeys added by \ref + //!< BridgeFinder::AddClientKey std::shared_ptr http_handler; }; @@ -145,12 +153,12 @@ public: //! \param username String that specifies the username that is used to control //! the bridge. Can be left empty and acquired in \ref requestUsername. //! \param handler HttpHandler for communication with the bridge + //! \param clientkey Optional client key for streaming //! \param refreshDuration Time between refreshing the cached state. //! \param sharedState Uses a single, shared cache for all objects on the bridge. Bridge(const std::string& ip, const int port, const std::string& username, - std::shared_ptr handler, - std::chrono::steady_clock::duration refreshDuration = std::chrono::seconds(10), - bool sharedState = false); + std::shared_ptr handler, const std::string& clientkey = "", + std::chrono::steady_clock::duration refreshDuration = std::chrono::seconds(10), bool sharedState = false); //! \brief Refreshes the bridge state. //! @@ -193,6 +201,11 @@ public: //! \return The username used for API access std::string getUsername() const; + //! \brief Function that returns the client key + //! + //! \return The client key used for Entertainment Mode API access + std::string getClientKey() const; + //! \brief Function to set the ip address of this class representing a bridge //! //! \param ip String that specifies the ip in dotted decimal notation like "192.168.2.1" @@ -245,6 +258,7 @@ public: //! \brief Provides access to the Rule%s on the bridge //! \note Does not refresh state. const RuleList& rules() const; + private: //! \brief Function that sets the HttpHandler and updates the HueCommandAPI. //! \param handler a HttpHandler of type \ref IHttpHandler @@ -259,6 +273,7 @@ private: std::string ip; //!< IP-Address of the hue bridge in dotted decimal notation //!< like "192.168.2.1" std::string username; //!< Username that is ussed to access the hue bridge + std::string clientkey; //!< Client key that is used for entertainment mode int port; std::shared_ptr http_handler; //!< A IHttpHandler that is used to communicate with the diff --git a/src/Bridge.cpp b/src/Bridge.cpp index f2db271..8af6ede 100644 --- a/src/Bridge.cpp +++ b/src/Bridge.cpp @@ -20,8 +20,6 @@ along with hueplusplus. If not, see . **/ -#include "hueplusplus/Bridge.h" - #include #include #include @@ -31,6 +29,7 @@ #include #include +#include "hueplusplus/Bridge.h" #include "hueplusplus/HueExceptionMacro.h" #include "hueplusplus/LibConfig.h" #include "hueplusplus/UPnP.h" @@ -79,10 +78,19 @@ Bridge BridgeFinder::GetBridge(const BridgeIdentification& identification, bool { std::string normalizedMac = NormalizeMac(identification.mac); auto pos = usernames.find(normalizedMac); + auto key = clientkeys.find(normalizedMac); if (pos != usernames.end()) { - return Bridge( - identification.ip, identification.port, pos->second, http_handler, std::chrono::seconds(10), sharedState); + if (key != clientkeys.end()) + { + return Bridge(identification.ip, identification.port, pos->second, http_handler, key->second, + std::chrono::seconds(10), sharedState); + } + else + { + return Bridge(identification.ip, identification.port, pos->second, http_handler, "", + std::chrono::seconds(10), sharedState); + } } Bridge bridge(identification.ip, identification.port, "", http_handler, std::chrono::seconds(10), sharedState); bridge.requestUsername(); @@ -92,6 +100,7 @@ Bridge BridgeFinder::GetBridge(const BridgeIdentification& identification, bool throw HueException(CURRENT_FILE_INFO, "Failed to request username!"); } AddUsername(normalizedMac, bridge.getUsername()); + AddClientKey(normalizedMac, bridge.getClientKey()); return bridge; } @@ -101,6 +110,11 @@ void BridgeFinder::AddUsername(const std::string& mac, const std::string& userna usernames[NormalizeMac(mac)] = username; } +void BridgeFinder::AddClientKey(const std::string& mac, const std::string& clientkey) +{ + clientkeys[NormalizeMac(mac)] = clientkey; +} + const std::map& BridgeFinder::GetAllUsernames() const { return usernames; @@ -139,9 +153,11 @@ std::string BridgeFinder::ParseDescription(const std::string& description) } Bridge::Bridge(const std::string& ip, const int port, const std::string& username, - std::shared_ptr handler, std::chrono::steady_clock::duration refreshDuration, bool sharedState) + std::shared_ptr handler, const std::string& clientkey, + std::chrono::steady_clock::duration refreshDuration, bool sharedState) : ip(ip), username(username), + clientkey(clientkey), port(port), http_handler(std::move(handler)), refreshDuration(refreshDuration), @@ -171,7 +187,6 @@ void Bridge::setRefreshDuration(std::chrono::steady_clock::duration refreshDurat stateCache->setRefreshDuration(refreshDuration); } - std::string Bridge::getBridgeIP() const { return ip; @@ -192,6 +207,7 @@ std::string Bridge::requestUsername() // when the link button was pressed we got 30 seconds to get our username for control nlohmann::json request; request["devicetype"] = "HuePlusPlus#User"; + request["generateclientkey"] = true; nlohmann::json answer; std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); @@ -201,6 +217,7 @@ std::string Bridge::requestUsername() std::this_thread::sleep_for(checkInterval); answer = http_handler->POSTJson("/api", request, ip, port); nlohmann::json jsonUser = utils::safeGetMember(answer, 0, "success", "username"); + nlohmann::json jsonKey = utils::safeGetMember(answer, 0, "success", "clientkey"); if (jsonUser != nullptr) { // [{"success":{"username": ""}}] @@ -209,6 +226,12 @@ std::string Bridge::requestUsername() setHttpHandler(http_handler); std::cout << "Success! Link button was pressed!\n"; std::cout << "Username is \"" << username << "\"\n"; + + if (jsonKey != nullptr) + { + clientkey = jsonKey.get(); + std::cout << "Client key is \"" << clientkey << "\"\n"; + } break; } else if (answer.size() > 0 && answer[0].count("error")) @@ -230,6 +253,11 @@ std::string Bridge::getUsername() const return username; } +std::string Bridge::getClientKey() const +{ + return clientkey; +} + void Bridge::setIP(const std::string& ip) { this->ip = ip;