diff --git a/hueplusplus/Hue.cpp b/hueplusplus/Hue.cpp index 0a2802f..9b4e71b 100755 --- a/hueplusplus/Hue.cpp +++ b/hueplusplus/Hue.cpp @@ -52,8 +52,11 @@ std::vector HueFinder::FindBridges() const { size_t start = p.first.find("//") + 2; size_t length = p.first.find(":", start) - start; bridge.ip = p.first.substr(start, length); + auto portLength = p.first.find("/", start + length) - (start + length + 1); + auto port = p.first.substr(start + length + 1, portLength); + bridge.port = std::stoi(port); std::string desc = http_handler->GETString( - "/description.xml", "application/xml", "", bridge.ip); + "/description.xml", "application/xml", "", bridge.ip, bridge.port); std::string mac = ParseDescription(desc); if (!mac.empty()) { bridge.mac = NormalizeMac(mac); @@ -68,9 +71,10 @@ Hue HueFinder::GetBridge(const HueIdentification &identification) { std::string normalizedMac = NormalizeMac(identification.mac); auto pos = usernames.find(normalizedMac); if (pos != usernames.end()) { - return Hue(identification.ip, pos->second, http_handler); + return Hue(identification.ip, identification.port, + pos->second, http_handler); } - Hue bridge(identification.ip, "", http_handler); + Hue bridge(identification.ip, identification.port, "", http_handler); bridge.requestUsername(identification.ip); if (bridge.getUsername().empty()) { std::cerr << "Failed to request username for ip " << identification.ip @@ -122,9 +126,9 @@ std::string HueFinder::ParseDescription(const std::string & description) return std::string(); } -Hue::Hue(const std::string &ip, const std::string &username, +Hue::Hue(const std::string &ip, const int port, const std::string &username, std::shared_ptr handler) - : ip(ip), username(username), + : ip(ip), port(port), username(username), simpleBrightnessStrategy(std::make_shared()), simpleColorHueStrategy(std::make_shared()), extendedColorHueStrategy(std::make_shared()), @@ -132,10 +136,13 @@ Hue::Hue(const std::string &ip, const std::string &username, std::make_shared()), extendedColorTemperatureStrategy( std::make_shared()), - http_handler(std::move(handler)), commands(ip, username, http_handler) {} + http_handler(std::move(handler)), commands(ip, port, username, + http_handler) {} std::string Hue::getBridgeIP() { return ip; } +int Hue::getBridgePort() { return port; } + std::string Hue::requestUsername(const std::string &ip) { std::cout << "Please press the link Button! You've got 35 secs!\n"; // when the link @@ -158,14 +165,14 @@ std::string Hue::requestUsername(const std::string &ip) { if (std::chrono::steady_clock::now() - lastCheck > std::chrono::seconds(1)) { lastCheck = std::chrono::steady_clock::now(); - answer = http_handler->POSTJson("/api", request, ip); + answer = http_handler->POSTJson("/api", request, ip, port); if (answer[0]["success"] != Json::nullValue) { // [{"success":{"username": ""}}] username = answer[0]["success"]["username"].asString(); this->ip = ip; // Update commands with new username and ip - commands = HueCommandAPI(ip, username, http_handler); + commands = HueCommandAPI(ip, port, username, http_handler); std::cout << "Success! Link button was pressed!\n"; std::cout << "Username is \"" << username << "\"\n"; break; @@ -182,6 +189,8 @@ std::string Hue::getUsername() { return username; } void Hue::setIP(const std::string &ip) { this->ip = ip; } +void Hue::setPort(const int port) { this->port = port; } + HueLight &Hue::getLight(int id) { auto pos = lights.find(id); if (pos != lights.end()) { diff --git a/hueplusplus/HueCommandAPI.cpp b/hueplusplus/HueCommandAPI.cpp index e9da475..2eedf4d 100755 --- a/hueplusplus/HueCommandAPI.cpp +++ b/hueplusplus/HueCommandAPI.cpp @@ -23,9 +23,10 @@ constexpr std::chrono::steady_clock::duration HueCommandAPI::minDelay; -HueCommandAPI::HueCommandAPI(const std::string &ip, const std::string &username, +HueCommandAPI::HueCommandAPI(const std::string &ip, const int port, + const std::string &username, std::shared_ptr httpHandler) - : ip(ip), username(username), httpHandler(std::move(httpHandler)), + : ip(ip), port(port), username(username), httpHandler(std::move(httpHandler)), timeout(new TimeoutData{std::chrono::steady_clock::now()}) {} Json::Value HueCommandAPI::PUTRequest(const std::string &path, @@ -40,7 +41,7 @@ Json::Value HueCommandAPI::PUTRequest(const std::string &path, "/api/" + username + (path.empty() || path.front() == '/' ? "" : "/") + path; try { - Json::Value v = httpHandler->PUTJson(combinedPath, request, ip); + Json::Value v = httpHandler->PUTJson(combinedPath, request, ip, port); timeout->timeout = now + minDelay; return v; } catch (const std::system_error &e) { @@ -69,7 +70,7 @@ Json::Value HueCommandAPI::GETRequest(const std::string &path, "/api/" + username + (path.empty() || path.front() == '/' ? "" : "/") + path; try { - Json::Value v = httpHandler->GETJson(combinedPath, request, ip); + Json::Value v = httpHandler->GETJson(combinedPath, request, ip, port); timeout->timeout = now + minDelay; return v; } catch (const std::system_error &e) { @@ -77,7 +78,7 @@ Json::Value HueCommandAPI::GETRequest(const std::string &path, e.code() == std::errc::timed_out) { // Happens when hue is too busy, wait and try again (once) std::this_thread::sleep_for(minDelay); - Json::Value v = httpHandler->GETJson(combinedPath, request, ip); + Json::Value v = httpHandler->GETJson(combinedPath, request, ip, port); timeout->timeout = std::chrono::steady_clock::now() + minDelay; return v; } @@ -98,7 +99,7 @@ Json::Value HueCommandAPI::DELETERequest(const std::string &path, "/api/" + username + (path.empty() || path.front() == '/' ? "" : "/") + path; try { - Json::Value v = httpHandler->DELETEJson(combinedPath, request, ip); + Json::Value v = httpHandler->DELETEJson(combinedPath, request, ip, port); timeout->timeout = now + minDelay; return v; } catch (const std::system_error &e) { @@ -106,7 +107,7 @@ Json::Value HueCommandAPI::DELETERequest(const std::string &path, e.code() == std::errc::timed_out) { // Happens when hue is too busy, wait and try again (once) std::this_thread::sleep_for(minDelay); - Json::Value v = httpHandler->DELETEJson(combinedPath, request, ip); + Json::Value v = httpHandler->DELETEJson(combinedPath, request, ip, port); timeout->timeout = std::chrono::steady_clock::now() + minDelay; return v; } diff --git a/hueplusplus/include/Hue.h b/hueplusplus/include/Hue.h index 8391e7d..95d1fb1 100755 --- a/hueplusplus/include/Hue.h +++ b/hueplusplus/include/Hue.h @@ -45,6 +45,7 @@ class HueFinder { public: struct HueIdentification { std::string ip; + int port = 80; std::string mac; }; @@ -107,18 +108,23 @@ public: //! \brief Constructor of Hue class //! //! \param ip String that specifies the ip address of the Hue bridge in dotted - //! decimal notation like "192.168.2.1" \param username String that specifies - //! the username that is used to control the bridge. This needs to be acquired - //! in \ref requestUsername \param handler HttpHandler of type \ref - //! IHttpHandler for communication with the bridge - Hue(const std::string &ip, const std::string &username, - std::shared_ptr handler); + //! decimal notation like "192.168.2.1" \param port Port of the hue bridge + //! \param username String that specifies the username that is used to control + //! the bridge. This needs to be acquired in \ref requestUsername \param handler + //! HttpHandler of type \ref IHttpHandler for communication with the bridge + Hue(const std::string &ip, const int port, const std::string &username, + std::shared_ptr handler); //! \brief Function to get the ip address of the hue bridge //! //! \return string containing ip std::string getBridgeIP(); + //! \brief Function to get the port of the hue bridge + //! + //! \return integer containing port + int getBridgePort(); + //! \brief Function that sends a username request to the Hue bridge. //! //! It does that for about 30 seconds and you have 5 seconds to prepare @@ -141,6 +147,12 @@ public: //! "192.168.2.1" void setIP(const std::string &ip); + //! \brief Function to set the port of this class representing a bridge + //! + //! \param port Integer that specifies the port of an address like + //! "192.168.2.1:8080" + void setPort(const int port); + //! \brief Function that returns a \ref Hue::HueLight of specified id //! //! \param id Integer that specifies the ID of a Hue light @@ -209,7 +221,7 @@ public: //! \param handler a HttpHandler of type \ref IHttpHandler void setHttpHandler(std::shared_ptr handler) { http_handler = std::move(handler); - commands = HueCommandAPI(ip, username, http_handler); + commands = HueCommandAPI(ip, port, username, http_handler); }; private: @@ -219,6 +231,7 @@ private: private: std::string ip; //!< IP-Address of the hue bridge in dotted decimal notation //!< like "192.168.2.1" + int port; std::string username; //!< Username that is ussed to access the hue bridge Json::Value state; //!< The state of the hue bridge as it is returned from it std::map diff --git a/hueplusplus/include/HueCommandAPI.h b/hueplusplus/include/HueCommandAPI.h index c0f204d..06ee4f5 100755 --- a/hueplusplus/include/HueCommandAPI.h +++ b/hueplusplus/include/HueCommandAPI.h @@ -33,10 +33,11 @@ public: //! \brief Construct from ip, username and HttpHandler //! //! \param ip String that specifies the ip address of the Hue bridge in dotted - //! decimal notation like "192.168.2.1" \param username String that specifies - //! the username that is used to control the bridge \param handler HttpHandler - //! of type \ref IHttpHandler for communication with the bridge - HueCommandAPI(const std::string &ip, const std::string &username, + //! decimal notation like "192.168.2.1" \param port of the hue bridge + //! \param username String that specifies the username that is used to control + //! the bridge \param handler HttpHandler of type \ref IHttpHandler for + //! communication with the bridge + HueCommandAPI(const std::string &ip, const int port, const std::string &username, std::shared_ptr httpHandler); //! \brief Copy construct from other HueCommandAPI @@ -100,6 +101,7 @@ private: static constexpr std::chrono::steady_clock::duration minDelay = std::chrono::milliseconds(100); std::string ip; + int port; std::string username; std::shared_ptr httpHandler; std::shared_ptr timeout; diff --git a/hueplusplus/test/mocks/mock_HueLight.h b/hueplusplus/test/mocks/mock_HueLight.h index 220e64a..23b6d54 100755 --- a/hueplusplus/test/mocks/mock_HueLight.h +++ b/hueplusplus/test/mocks/mock_HueLight.h @@ -33,7 +33,9 @@ class MockHueLight : public HueLight { public: - MockHueLight(std::shared_ptr handler) : HueLight(1, HueCommandAPI(getBridgeIp(), getBridgeUsername(), handler)) {}; + MockHueLight(std::shared_ptr handler) : HueLight(1, + HueCommandAPI(getBridgeIp(), getBridgePort(), getBridgeUsername(), + handler)) {}; Json::Value& getState() { return state; }; diff --git a/hueplusplus/test/test_Hue.cpp b/hueplusplus/test/test_Hue.cpp index fbc5410..b3a351d 100755 --- a/hueplusplus/test/test_Hue.cpp +++ b/hueplusplus/test/test_Hue.cpp @@ -45,16 +45,19 @@ TEST_F(HueFinderTest, FindBridges) { HueFinder::HueIdentification bridge_to_comp; bridge_to_comp.ip = getBridgeIp(); + bridge_to_comp.port = getBridgePort(); bridge_to_comp.mac = getBridgeMac(); EXPECT_EQ(bridges.size(), 1) << "HueFinder found more than one Bridge"; EXPECT_EQ(bridges[0].ip, bridge_to_comp.ip) << "HueIdentification ip does not match"; + EXPECT_EQ(bridges[0].port, bridge_to_comp.port) + << "HueIdentification port does not match"; EXPECT_EQ(bridges[0].mac, bridge_to_comp.mac) << "HueIdentification mac does not match"; // Test invalid description - EXPECT_CALL(*handler, GETString("/description.xml", "application/xml", "", getBridgeIp(), 80)) + EXPECT_CALL(*handler, GETString("/description.xml", "application/xml", "", getBridgeIp(), getBridgePort())) .Times(1) .WillOnce(::testing::Return("invalid stuff")); bridges = finder.FindBridges(); @@ -100,6 +103,8 @@ TEST_F(HueFinderTest, GetBridge) { EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching"; + EXPECT_EQ(test_bridge.getBridgePort(), getBridgePort()) + << "Bridge Port not matching"; EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching"; @@ -126,6 +131,8 @@ TEST_F(HueFinderTest, AddUsername) { EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching"; + EXPECT_EQ(test_bridge.getBridgePort(), getBridgePort()) + << "Bridge Port not matching"; EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching"; } @@ -144,10 +151,12 @@ TEST_F(HueFinderTest, GetAllUsernames) { TEST(Hue, Constructor) { std::shared_ptr handler = std::make_shared(); - Hue test_bridge(getBridgeIp(), getBridgeUsername(), handler); + Hue test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching"; + EXPECT_EQ(test_bridge.getBridgePort(), getBridgePort()) + << "Bridge Port not matching"; EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching"; } @@ -167,11 +176,11 @@ TEST(Hue, requestUsername) { user_ret_uns[0]["error"]["address"] = ""; user_ret_uns[0]["error"]["description"] = "link button not pressed"; - EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), 80)) + EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort())) .Times(AtLeast(1)) .WillRepeatedly(Return(user_ret_uns)); - Hue test_bridge(getBridgeIp(), "", handler); + Hue test_bridge(getBridgeIp(), getBridgePort(), "", handler); test_bridge.requestUsername(test_bridge.getBridgeIP()); EXPECT_EQ(test_bridge.getUsername(), "") << "Bridge username not matching"; @@ -185,7 +194,7 @@ TEST(Hue, requestUsername) { .Times(1) .WillRepeatedly(Return(user_ret_suc)); - test_bridge = Hue(getBridgeIp(), "", handler); + test_bridge = Hue(getBridgeIp(), getBridgePort(), "", handler); test_bridge.requestUsername(test_bridge.getBridgeIP()); @@ -209,7 +218,7 @@ TEST(Hue, requestUsername) { TEST(Hue, setIP) { std::shared_ptr handler = std::make_shared(); - Hue test_bridge(getBridgeIp(), "", handler); + Hue test_bridge = Hue(getBridgeIp(), getBridgePort(), "", handler); EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching after initialization"; test_bridge.setIP("192.168.2.112"); @@ -217,6 +226,17 @@ TEST(Hue, setIP) { << "Bridge IP not matching after setting it"; } +TEST(Hue, setPort) { + std::shared_ptr handler = + std::make_shared(); + Hue test_bridge = Hue(getBridgeIp(), getBridgePort(), "", handler); + EXPECT_EQ(test_bridge.getBridgePort(), getBridgePort()) + << "Bridge Port not matching after initialization"; + test_bridge.setPort(81); + EXPECT_EQ(test_bridge.getBridgePort(), 81) + << "Bridge Port not matching after setting it"; +} + TEST(Hue, getLight) { using namespace ::testing; std::shared_ptr handler = @@ -226,7 +246,7 @@ TEST(Hue, getLight) { Json::Value(Json::objectValue), getBridgeIp(), 80)) .Times(1); - Hue test_bridge(getBridgeIp(), getBridgeUsername(), handler); + Hue test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); // Test exception ASSERT_THROW(test_bridge.getLight(1), std::runtime_error); @@ -286,7 +306,7 @@ TEST(Hue, getLight) { Json::Value(Json::objectValue), getBridgeIp(), 80)) .Times(AtLeast(1)) .WillRepeatedly(Return(hue_bridge_state["lights"]["1"])); - test_bridge = Hue(getBridgeIp(), getBridgeUsername(), handler); + test_bridge = Hue(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); // Test when correct data is sent test_light_1 = test_bridge.getLight(1); @@ -305,7 +325,7 @@ TEST(Hue, getLight) { Json::Value(Json::objectValue), getBridgeIp(), 80)) .Times(AtLeast(1)) .WillRepeatedly(Return(hue_bridge_state["lights"]["1"])); - test_bridge = Hue(getBridgeIp(), getBridgeUsername(), handler); + test_bridge = Hue(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); // Test when correct data is sent test_light_1 = test_bridge.getLight(1); @@ -324,7 +344,7 @@ TEST(Hue, getLight) { Json::Value(Json::objectValue), getBridgeIp(), 80)) .Times(AtLeast(1)) .WillRepeatedly(Return(hue_bridge_state["lights"]["1"])); - test_bridge = Hue(getBridgeIp(), getBridgeUsername(), handler); + test_bridge = Hue(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); // Test when correct data is sent test_light_1 = test_bridge.getLight(1); @@ -343,7 +363,7 @@ TEST(Hue, getLight) { Json::Value(Json::objectValue), getBridgeIp(), 80)) .Times(AtLeast(1)) .WillRepeatedly(Return(hue_bridge_state["lights"]["1"])); - test_bridge = Hue(getBridgeIp(), getBridgeUsername(), handler); + test_bridge = Hue(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); // Test when correct data is sent test_light_1 = test_bridge.getLight(1); @@ -356,7 +376,7 @@ TEST(Hue, getLight) { Json::Value(Json::objectValue), getBridgeIp(), 80)) .Times(1) .WillOnce(Return(hue_bridge_state)); - test_bridge = Hue(getBridgeIp(), getBridgeUsername(), handler); + test_bridge = Hue(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); ASSERT_THROW(test_bridge.getLight(1), std::runtime_error); } @@ -390,7 +410,7 @@ TEST(Hue, removeLight) { .Times(1) .WillOnce(Return(hue_bridge_state)); - Hue test_bridge(getBridgeIp(), getBridgeUsername(), handler); + Hue test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); EXPECT_CALL(*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", @@ -452,7 +472,7 @@ TEST(Hue, getAllLights) { .Times(2) .WillRepeatedly(Return(hue_bridge_state["lights"]["1"])); - Hue test_bridge(getBridgeIp(), getBridgeUsername(), handler); + Hue test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); std::vector> test_lights = test_bridge.getAllLights(); @@ -495,7 +515,7 @@ TEST(Hue, lightExists) { .Times(AtLeast(1)) .WillRepeatedly(Return(hue_bridge_state["lights"]["1"])); - Hue test_bridge(getBridgeIp(), getBridgeUsername(), handler); + Hue test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); EXPECT_EQ(true, test_bridge.lightExists(1)); EXPECT_EQ(false, test_bridge.lightExists(2)); @@ -545,7 +565,7 @@ TEST(Hue, getPictureOfLight) { .Times(AtLeast(1)) .WillRepeatedly(Return(hue_bridge_state["lights"]["1"])); - Hue test_bridge(getBridgeIp(), getBridgeUsername(), handler); + Hue test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler); test_bridge.getLight(1); @@ -557,7 +577,7 @@ TEST(Hue, getPictureOfLight) { TEST(Hue, refreshState) { std::shared_ptr handler = std::make_shared(); - Hue test_bridge(getBridgeIp(), "", + Hue test_bridge(getBridgeIp(), getBridgePort(), "", handler); // NULL as username leads to segfault std::vector> test_lights = diff --git a/hueplusplus/test/test_HueCommandAPI.cpp b/hueplusplus/test/test_HueCommandAPI.cpp index 702b1b5..353eee2 100755 --- a/hueplusplus/test/test_HueCommandAPI.cpp +++ b/hueplusplus/test/test_HueCommandAPI.cpp @@ -30,7 +30,8 @@ TEST(HueCommandAPI, PUTRequest) { std::shared_ptr httpHandler = std::make_shared(); - HueCommandAPI api(getBridgeIp(), getBridgeUsername(), httpHandler); + HueCommandAPI api(getBridgeIp(), getBridgePort(), getBridgeUsername(), + httpHandler); Json::Value request; Json::Value result = Json::objectValue; result["ok"] = true; @@ -102,7 +103,8 @@ TEST(HueCommandAPI, GETRequest) { std::shared_ptr httpHandler = std::make_shared(); - HueCommandAPI api(getBridgeIp(), getBridgeUsername(), httpHandler); + HueCommandAPI api(getBridgeIp(), getBridgePort(), getBridgeUsername(), + httpHandler); Json::Value request; Json::Value result = Json::objectValue; result["ok"] = true; @@ -174,7 +176,8 @@ TEST(HueCommandAPI, DELETERequest) { std::shared_ptr httpHandler = std::make_shared(); - HueCommandAPI api(getBridgeIp(), getBridgeUsername(), httpHandler); + HueCommandAPI api(getBridgeIp(), getBridgePort(), getBridgeUsername(), + httpHandler); Json::Value request; Json::Value result = Json::objectValue; result["ok"] = true; diff --git a/hueplusplus/test/test_HueLight.cpp b/hueplusplus/test/test_HueLight.cpp index 1084673..e25c3f5 100755 --- a/hueplusplus/test/test_HueLight.cpp +++ b/hueplusplus/test/test_HueLight.cpp @@ -16,7 +16,8 @@ protected: protected: HueLightTest() : handler(std::make_shared()), - test_bridge(getBridgeIp(), getBridgeUsername(), handler) { + test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), + handler) { using namespace ::testing; hue_bridge_state["lights"] = Json::Value(Json::objectValue); hue_bridge_state["lights"]["1"] = Json::Value(Json::objectValue); diff --git a/hueplusplus/test/testhelper.h b/hueplusplus/test/testhelper.h index cd71cff..4aa9177 100755 --- a/hueplusplus/test/testhelper.h +++ b/hueplusplus/test/testhelper.h @@ -6,6 +6,10 @@ inline std::string getBridgeIp() { //!< decimal notation like "192.168.2.1" } +inline int getBridgePort() { + return 80; +} + inline std::string getBridgeUsername() { return "83b7780291a6ceffbe0bd049104df"; //!< Username that is ussed to access //!< the fake hue bridge