diff --git a/include/hueplusplus/Hue.h b/include/hueplusplus/Hue.h index 5b7680a..9c7d1cb 100644 --- a/include/hueplusplus/Hue.h +++ b/include/hueplusplus/Hue.h @@ -360,7 +360,6 @@ private: std::shared_ptr http_handler; //!< A IHttpHandler that is used to communicate with the //!< bridge - std::chrono::steady_clock::duration refreshDuration; std::shared_ptr stateCache; ResourceList lights; diff --git a/include/hueplusplus/HueCommandAPI.h b/include/hueplusplus/HueCommandAPI.h index 0706a7e..63ddc96 100644 --- a/include/hueplusplus/HueCommandAPI.h +++ b/include/hueplusplus/HueCommandAPI.h @@ -135,9 +135,6 @@ private: //! \returns "/api//" std::string CombinedPath(const std::string& path) const; -public: - static constexpr std::chrono::steady_clock::duration minDelay = std::chrono::milliseconds(100); - private: std::string ip; int port; diff --git a/include/hueplusplus/HueConfig.h b/include/hueplusplus/HueConfig.h index b4820e9..3a592e8 100644 --- a/include/hueplusplus/HueConfig.h +++ b/include/hueplusplus/HueConfig.h @@ -23,10 +23,53 @@ #ifndef INCLUDE_HUEPLUSPLUS_HUE_CONFIG_H #define INCLUDE_HUEPLUSPLUS_HUE_CONFIG_H +#include + namespace hueplusplus { -constexpr uint16_t c_PRE_ALERT_DELAY = 120; //!< Delay for advanced alerts before the actual alert -constexpr uint16_t c_POST_ALERT_DELAY = 1600; //!< Delay for advanced alerts after the actual alert +//! \brief Configurable delays +//! +//! Used to set all delays to zero when running tests. +class Config +{ +private: + using duration = std::chrono::steady_clock::duration; + +public: + //! \brief Delay for advanced alerts before the actual alert + duration getPreAlertDelay() const { return preAlertDelay; } + //! \brief Delay for advanced alerts after the actual alert + duration getPostAlertDelay() const { return postAlertDelay; } + + //! \brief Timeout for UPnP multicast request + duration getUPnPTimeout() const { return upnpTimeout; } + + //! \brief Delay between bridge requests + duration getBridgeRequestDelay() const { return bridgeRequestDelay; } + + //! \brief Timeout for Hue::requestUsername, waits until link button was pressed + duration getRequestUsernameTimeout() const { return requestUsernameDelay; } + + //! \brief Interval in which username requests are attempted + duration getRequestUsernameAttemptInterval() const { return requestUsernameAttemptInterval; } + + //! \brief Get config instance + static Config& instance() + { + static Config c; + return c; + } +protected: + Config() = default; + +protected: + duration preAlertDelay = std::chrono::milliseconds(120); + duration postAlertDelay = std::chrono::milliseconds(1600); + duration upnpTimeout = std::chrono::seconds(5); + duration bridgeRequestDelay = std::chrono::milliseconds(100); + duration requestUsernameDelay = std::chrono::seconds(35); + duration requestUsernameAttemptInterval = std::chrono::seconds(1); +}; } // namespace hueplusplus #endif diff --git a/include/hueplusplus/IHttpHandler.h b/include/hueplusplus/IHttpHandler.h index c45b288..6deefa7 100644 --- a/include/hueplusplus/IHttpHandler.h +++ b/include/hueplusplus/IHttpHandler.h @@ -23,6 +23,7 @@ #ifndef INCLUDE_HUEPLUSPLUS_IHTTPHANDLER_H #define INCLUDE_HUEPLUSPLUS_IHTTPHANDLER_H +#include #include #include #include @@ -63,14 +64,14 @@ public: //! \param msg The message that should sent to the specified multicast address //! \param adr Optional ip or hostname in dotted decimal notation, default is "239.255.255.250" //! \param port Optional port the request is sent to, default is 1900 - //! \param timeout Optional time to wait for responses in seconds, default is 5 + //! \param timeout Optional time to wait for responses, default is 5 seconds //! //! Blocks for the duration of the timeout. //! //! \return vector of strings containing each received answer //! \throws std::system_error when system or socket operations fail - virtual std::vector sendMulticast( - const std::string& msg, const std::string& adr = "239.255.255.250", int port = 1900, int timeout = 5) const = 0; + virtual std::vector sendMulticast(const std::string& msg, const std::string& adr = "239.255.255.250", + int port = 1900, std::chrono::steady_clock::duration timeout = std::chrono::seconds(5)) const = 0; //! \brief Send a HTTP request with the given method to the specified host and return the body of the response. //! diff --git a/include/hueplusplus/LinHttpHandler.h b/include/hueplusplus/LinHttpHandler.h index f284ea2..2d13faf 100644 --- a/include/hueplusplus/LinHttpHandler.h +++ b/include/hueplusplus/LinHttpHandler.h @@ -52,11 +52,11 @@ public: //! address \param adr Optional String that contains an ip or hostname in //! dotted decimal notation, default is "239.255.255.250" \param port Optional //! integer that specifies the port to which the request is sent. Default is - //! 1900 \param timeout Optional Integer that specifies the timeout of the - //! request in seconds. Default is 5 \return Vector containing strings of each + //! 1900 \param timeout Optional The timeout of the + //! request. Default is 5 seconds \return Vector containing strings of each //! answer received - virtual std::vector sendMulticast( - const std::string& msg, const std::string& adr = "239.255.255.250", int port = 1900, int timeout = 5) const; + std::vector sendMulticast(const std::string& msg, const std::string& adr = "239.255.255.250", + int port = 1900, std::chrono::steady_clock::duration timeout = std::chrono::seconds(5)) const override; }; } // namespace hueplusplus diff --git a/include/hueplusplus/WinHttpHandler.h b/include/hueplusplus/WinHttpHandler.h index 1c7976d..657a67d 100644 --- a/include/hueplusplus/WinHttpHandler.h +++ b/include/hueplusplus/WinHttpHandler.h @@ -58,11 +58,11 @@ public: //! address \param adr Optional String that contains an ip or hostname in //! dotted decimal notation, default is "239.255.255.250" \param port Optional //! integer that specifies the port to which the request is sent. Default is - //! 1900 \param timeout Optional Integer that specifies the timeout of the - //! request in seconds. Default is 5 \return Vector containing strings of each + //! 1900 \param timeout Optional The timeout of the + //! request. Default is 5 seconds \return Vector containing strings of each //! answer received std::vector sendMulticast(const std::string& msg, const std::string& adr = "239.255.255.250", - int port = 1900, int timeout = 5) const override; + int port = 1900, std::chrono::steady_clock::duration timeout = std::chrono::seconds(5)) const override; private: WSADATA wsaData; diff --git a/src/ExtendedColorHueStrategy.cpp b/src/ExtendedColorHueStrategy.cpp index 67be19e..4150b5f 100644 --- a/src/ExtendedColorHueStrategy.cpp +++ b/src/ExtendedColorHueStrategy.cpp @@ -44,12 +44,12 @@ bool ExtendedColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, Hue { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorHueSaturation(oldHue, oldSat, 1); @@ -68,12 +68,12 @@ bool ExtendedColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, Hue { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorXY(oldX, oldY, 1); @@ -91,12 +91,12 @@ bool ExtendedColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, Hue { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorTemperature(oldCT, 1); @@ -127,12 +127,12 @@ bool ExtendedColorHueStrategy::alertXY(float x, float y, HueLight& light) const { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorHueSaturation(oldHue, oldSat, 1); @@ -151,12 +151,12 @@ bool ExtendedColorHueStrategy::alertXY(float x, float y, HueLight& light) const { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorXY(oldX, oldY, 1); @@ -174,12 +174,12 @@ bool ExtendedColorHueStrategy::alertXY(float x, float y, HueLight& light) const { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorTemperature(oldCT, 1); @@ -210,12 +210,12 @@ bool ExtendedColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLigh { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorHueSaturation(oldHue, oldSat, 1); @@ -234,12 +234,12 @@ bool ExtendedColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLigh { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorXY(oldX, oldY, 1); @@ -257,12 +257,12 @@ bool ExtendedColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLigh { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorTemperature(oldCT, 1); diff --git a/src/ExtendedColorTemperatureStrategy.cpp b/src/ExtendedColorTemperatureStrategy.cpp index c6a438b..2999863 100644 --- a/src/ExtendedColorTemperatureStrategy.cpp +++ b/src/ExtendedColorTemperatureStrategy.cpp @@ -85,12 +85,12 @@ bool ExtendedColorTemperatureStrategy::alertTemperature(unsigned int mired, HueL { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorHueSaturation(oldHue, oldSat, 1); @@ -109,12 +109,12 @@ bool ExtendedColorTemperatureStrategy::alertTemperature(unsigned int mired, HueL { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorXY(oldX, oldY, 1); @@ -132,12 +132,12 @@ bool ExtendedColorTemperatureStrategy::alertTemperature(unsigned int mired, HueL { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorTemperature(oldCT, 1); diff --git a/src/Hue.cpp b/src/Hue.cpp index 7c6916a..4fc0667 100644 --- a/src/Hue.cpp +++ b/src/Hue.cpp @@ -31,6 +31,7 @@ #include #include +#include "hueplusplus/HueConfig.h" #include "hueplusplus/HueExceptionMacro.h" #include "hueplusplus/UPnP.h" #include "hueplusplus/Utils.h" @@ -160,51 +161,44 @@ int Hue::getBridgePort() const std::string Hue::requestUsername() { - std::cout << "Please press the link Button! You've got 35 secs!\n"; // when the link - // button was - // pressed we - // got 30 - // seconds to - // get our - // username for - // control + std::chrono::steady_clock::duration timeout = Config::instance().getRequestUsernameTimeout(); + std::chrono::steady_clock::duration checkInterval = Config::instance().getRequestUsernameAttemptInterval(); + std::cout << "Please press the link Button! You've got " + << std::chrono::duration_cast(timeout).count() << " secs!\n"; + // when the link button was pressed we got 30 seconds to get our username for control nlohmann::json request; request["devicetype"] = "HuePlusPlus#User"; nlohmann::json answer; std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); - std::chrono::steady_clock::time_point lastCheck; - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(35)) + // do-while loop to check at least once when timeout is 0 + do { - if (std::chrono::steady_clock::now() - lastCheck > std::chrono::seconds(1)) + std::this_thread::sleep_for(checkInterval); + answer = http_handler->POSTJson("/api", request, ip, port); + nlohmann::json jsonUser = utils::safeGetMember(answer, 0, "success", "username"); + if (jsonUser != nullptr) { - lastCheck = std::chrono::steady_clock::now(); - answer = http_handler->POSTJson("/api", request, ip, port); - nlohmann::json jsonUser = utils::safeGetMember(answer, 0, "success", "username"); - if (jsonUser != nullptr) - { - // [{"success":{"username": ""}}] - username = jsonUser.get(); - // Update commands with new username and ip - setHttpHandler(http_handler); - std::cout << "Success! Link button was pressed!\n"; - std::cout << "Username is \"" << username << "\"\n"; - break; - } - else if (answer.size() > 0 && answer[0].count("error")) + // [{"success":{"username": ""}}] + username = jsonUser.get(); + // Update commands with new username and ip + setHttpHandler(http_handler); + std::cout << "Success! Link button was pressed!\n"; + std::cout << "Username is \"" << username << "\"\n"; + break; + } + else if (answer.size() > 0 && answer[0].count("error")) + { + HueAPIResponseException exception = HueAPIResponseException::Create(CURRENT_FILE_INFO, answer[0]); + // All errors except 101: Link button not pressed + if (exception.GetErrorNumber() != 101) { - HueAPIResponseException exception = HueAPIResponseException::Create(CURRENT_FILE_INFO, answer[0]); - // All errors except 101: Link button not pressed - if (exception.GetErrorNumber() != 101) - { - throw exception; - } + throw exception; } - - std::this_thread::sleep_until(lastCheck + std::chrono::seconds(1)); } - } + } while (std::chrono::steady_clock::now() - start < timeout); + return username; } @@ -425,9 +419,10 @@ std::string Hue::getPictureOfModel(const std::string& model_id) const void Hue::setHttpHandler(std::shared_ptr handler) { http_handler = handler; - stateCache = std::make_shared("", HueCommandAPI(ip, port, username, handler), refreshDuration); + stateCache + = std::make_shared("", HueCommandAPI(ip, port, username, handler), stateCache->getRefreshDuration()); lights = ResourceList("/lights", stateCache, "lights", - [factory = HueLightFactory(stateCache->getCommandAPI(), refreshDuration)]( + [factory = HueLightFactory(stateCache->getCommandAPI(), stateCache->getRefreshDuration())]( int id, const nlohmann::json& state) mutable { return factory.createLight(state, id); }); groups = CreateableResourceList("/groups", stateCache, "groups"); schedules = CreateableResourceList("/schedules", stateCache, "schedules"); diff --git a/src/HueCommandAPI.cpp b/src/HueCommandAPI.cpp index 93b5349..4ae7986 100644 --- a/src/HueCommandAPI.cpp +++ b/src/HueCommandAPI.cpp @@ -24,12 +24,11 @@ #include +#include "hueplusplus/HueConfig.h" #include "hueplusplus/HueExceptionMacro.h" namespace hueplusplus { -constexpr std::chrono::steady_clock::duration HueCommandAPI::minDelay; - namespace { // Runs functor with appropriate timeout and retries when timed out or connection reset @@ -81,7 +80,7 @@ nlohmann::json HueCommandAPI::PUTRequest(const std::string& path, const nlohmann nlohmann::json HueCommandAPI::PUTRequest( const std::string& path, const nlohmann::json& request, FileInfo fileInfo) const { - return HandleError(std::move(fileInfo), RunWithTimeout(timeout, minDelay, [&]() { + return HandleError(std::move(fileInfo), RunWithTimeout(timeout, Config::instance().getBridgeRequestDelay(), [&]() { return httpHandler->PUTJson(CombinedPath(path), request, ip, port); })); } @@ -94,7 +93,7 @@ nlohmann::json HueCommandAPI::GETRequest(const std::string& path, const nlohmann nlohmann::json HueCommandAPI::GETRequest( const std::string& path, const nlohmann::json& request, FileInfo fileInfo) const { - return HandleError(std::move(fileInfo), RunWithTimeout(timeout, minDelay, [&]() { + return HandleError(std::move(fileInfo), RunWithTimeout(timeout, Config::instance().getBridgeRequestDelay(), [&]() { return httpHandler->GETJson(CombinedPath(path), request, ip, port); })); } @@ -107,7 +106,7 @@ nlohmann::json HueCommandAPI::DELETERequest(const std::string& path, const nlohm nlohmann::json HueCommandAPI::DELETERequest( const std::string& path, const nlohmann::json& request, FileInfo fileInfo) const { - return HandleError(std::move(fileInfo), RunWithTimeout(timeout, minDelay, [&]() { + return HandleError(std::move(fileInfo), RunWithTimeout(timeout, Config::instance().getBridgeRequestDelay(), [&]() { return httpHandler->DELETEJson(CombinedPath(path), request, ip, port); })); } @@ -120,7 +119,7 @@ nlohmann::json HueCommandAPI::POSTRequest(const std::string& path, const nlohman nlohmann::json HueCommandAPI::POSTRequest( const std::string& path, const nlohmann::json& request, FileInfo fileInfo) const { - return HandleError(std::move(fileInfo), RunWithTimeout(timeout, minDelay, [&]() { + return HandleError(std::move(fileInfo), RunWithTimeout(timeout, Config::instance().getBridgeRequestDelay(), [&]() { return httpHandler->POSTJson(CombinedPath(path), request, ip, port); })); } diff --git a/src/LinHttpHandler.cpp b/src/LinHttpHandler.cpp index e833f25..5616e18 100644 --- a/src/LinHttpHandler.cpp +++ b/src/LinHttpHandler.cpp @@ -139,7 +139,7 @@ std::string LinHttpHandler::send(const std::string& msg, const std::string& adr, } std::vector LinHttpHandler::sendMulticast( - const std::string& msg, const std::string& adr, int port, int timeout) const + const std::string& msg, const std::string& adr, int port, std::chrono::steady_clock::duration timeout) const { hostent* server; // host information sockaddr_in server_addr; // server address @@ -187,7 +187,7 @@ std::vector LinHttpHandler::sendMulticast( char buffer[2048] = {}; // receive buffer std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout)) + while (std::chrono::steady_clock::now() - start < timeout) { ssize_t bytesReceived = recv(socketFD, &buffer, 2048, MSG_DONTWAIT); if (bytesReceived < 0) diff --git a/src/SimpleColorHueStrategy.cpp b/src/SimpleColorHueStrategy.cpp index a2e1f06..b1dbd35 100644 --- a/src/SimpleColorHueStrategy.cpp +++ b/src/SimpleColorHueStrategy.cpp @@ -97,12 +97,12 @@ bool SimpleColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, HueLi { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorHueSaturation(oldHue, oldSat, 1); @@ -121,12 +121,12 @@ bool SimpleColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, HueLi { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorXY(oldX, oldY, 1); @@ -157,12 +157,12 @@ bool SimpleColorHueStrategy::alertXY(float x, float y, HueLight& light) const { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorHueSaturation(oldHue, oldSat, 1); @@ -181,12 +181,12 @@ bool SimpleColorHueStrategy::alertXY(float x, float y, HueLight& light) const { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorXY(oldX, oldY, 1); @@ -217,12 +217,12 @@ bool SimpleColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLight& { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorHueSaturation(oldHue, oldSat, 1); @@ -241,12 +241,12 @@ bool SimpleColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLight& { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorXY(oldX, oldY, 1); diff --git a/src/SimpleColorTemperatureStrategy.cpp b/src/SimpleColorTemperatureStrategy.cpp index bcc9f47..2b11c6d 100644 --- a/src/SimpleColorTemperatureStrategy.cpp +++ b/src/SimpleColorTemperatureStrategy.cpp @@ -50,12 +50,12 @@ bool SimpleColorTemperatureStrategy::alertTemperature(unsigned int mired, HueLig { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPreAlertDelay()); if (!light.alert()) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY)); + std::this_thread::sleep_for(Config::instance().getPostAlertDelay()); if (!on) { light.setColorTemperature(oldCT, 1); diff --git a/src/UPnP.cpp b/src/UPnP.cpp index f617864..f691155 100644 --- a/src/UPnP.cpp +++ b/src/UPnP.cpp @@ -25,6 +25,8 @@ #include #include +#include "hueplusplus/HueConfig.h" + namespace hueplusplus { std::vector> UPnP::getDevices(std::shared_ptr handler) @@ -33,7 +35,7 @@ std::vector> UPnP::getDevices(std::shared_pt std::vector foundDevices = handler->sendMulticast("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: " "\"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n", - "239.255.255.250", 1900, 5); + "239.255.255.250", 1900, Config::instance().getUPnPTimeout()); std::vector> devices; @@ -41,9 +43,19 @@ std::vector> UPnP::getDevices(std::shared_pt for (const std::string& s : foundDevices) { std::pair device; - int start = s.find("LOCATION:") + 10; + std::size_t start = s.find("LOCATION:"); + if (start == std::string::npos) + { + continue; + } + start += 10; device.first = s.substr(start, s.find("\r\n", start) - start); - start = s.find("SERVER:") + 8; + start = s.find("SERVER:"); + if (start == std::string::npos) + { + continue; + } + start += 8; device.second = s.substr(start, s.find("\r\n", start) - start); if (std::find_if(devices.begin(), devices.end(), [&](const std::pair& item) { return item.first == device.first; }) diff --git a/src/WinHttpHandler.cpp b/src/WinHttpHandler.cpp index 82d4b5f..6014e97 100644 --- a/src/WinHttpHandler.cpp +++ b/src/WinHttpHandler.cpp @@ -174,7 +174,7 @@ std::string WinHttpHandler::send(const std::string& msg, const std::string& adr, } std::vector WinHttpHandler::sendMulticast( - const std::string& msg, const std::string& adr, int port, int timeout) const + const std::string& msg, const std::string& adr, int port, std::chrono::steady_clock::duration timeout) const { struct addrinfo hints = {}; hints.ai_family = AF_INET; @@ -262,7 +262,7 @@ std::vector WinHttpHandler::sendMulticast( const int recvbuflen = 2048; char recvbuf[recvbuflen] = {}; std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout)) + while (std::chrono::steady_clock::now() - start < timeout) { int res = recv(connect_socket, recvbuf, recvbuflen, 0); if (res > 0) diff --git a/test/mocks/mock_BaseHttpHandler.h b/test/mocks/mock_BaseHttpHandler.h index 871c628..f38f1c5 100644 --- a/test/mocks/mock_BaseHttpHandler.h +++ b/test/mocks/mock_BaseHttpHandler.h @@ -38,7 +38,7 @@ public: MOCK_CONST_METHOD3(send, std::string(const std::string& msg, const std::string& adr, int port)); MOCK_CONST_METHOD4( - sendMulticast, std::vector(const std::string& msg, const std::string& adr, int port, int timeout)); + sendMulticast, std::vector(const std::string& msg, const std::string& adr, int port, std::chrono::steady_clock::duration timeout)); }; #endif diff --git a/test/mocks/mock_HttpHandler.h b/test/mocks/mock_HttpHandler.h index df76420..4026375 100644 --- a/test/mocks/mock_HttpHandler.h +++ b/test/mocks/mock_HttpHandler.h @@ -39,8 +39,9 @@ public: MOCK_CONST_METHOD3(sendGetHTTPBody, std::string(const std::string& msg, const std::string& adr, int port)); - MOCK_CONST_METHOD4( - sendMulticast, std::vector(const std::string& msg, const std::string& adr, int port, int timeout)); + MOCK_CONST_METHOD4(sendMulticast, + std::vector( + const std::string& msg, const std::string& adr, int port, std::chrono::steady_clock::duration timeout)); MOCK_CONST_METHOD6(sendHTTPRequest, std::string(const std::string& method, const std::string& uri, const std::string& content_type, diff --git a/test/test_Hue.cpp b/test/test_Hue.cpp index 13b5bb8..800ec87 100644 --- a/test/test_Hue.cpp +++ b/test/test_Hue.cpp @@ -29,6 +29,7 @@ #include "testhelper.h" #include "hueplusplus/Hue.h" +#include "hueplusplus/HueConfig.h" #include "json/json.hpp" #include "mocks/mock_HttpHandler.h" @@ -47,7 +48,7 @@ protected: EXPECT_CALL(*handler, sendMulticast("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: " "\"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n", - "239.255.255.250", 1900, 5)) + "239.255.255.250", 1900, Config::instance().getUPnPTimeout())) .Times(AtLeast(1)) .WillRepeatedly(Return(getMulticastReply())); diff --git a/test/test_HueLight.cpp b/test/test_HueLight.cpp index 64acb33..14c1591 100644 --- a/test/test_HueLight.cpp +++ b/test/test_HueLight.cpp @@ -42,73 +42,35 @@ protected: protected: HueLightTest() : handler(std::make_shared()), + hue_bridge_state({{"lights", + {{"1", + {{"state", + {{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"}, + {"reachable", true}, {"effect", "none"}}}, + {"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Dimmable light"}, + {"name", "Hue lamp 1"}, {"modelid", "LWB004"}, {"manufacturername", "Philips"}, + {"productname", "Hue bloom"}, {"uniqueid", "00:00:00:00:00:00:00:00-00"}, + {"swversion", "5.50.1.19085"}, {"luminaireuniqueid", "0000000"}}}, + {"2", + {{"state", + {{"on", false}, {"bri", 0}, {"ct", 366}, {"hue", 12345}, {"sat", 123}, + {"xy", {0.102, 0.102}}, {"alert", "none"}, {"colormode", "ct"}, {"reachable", true}, + {"effect", "none"}}}, + {"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color light"}, + {"name", "Hue lamp 2"}, {"modelid", "LST001"}, {"uniqueid", "11:11:11:11:11:11:11:11-11"}, + {"swversion", "5.50.1.19085"}}}, + {"3", + {{"state", + {{"on", false}, {"bri", 254}, {"ct", 366}, {"hue", 12345}, {"sat", 123}, + {"xy", {0.102, 0.102}}, {"alert", "none"}, {"colormode", "ct"}, {"reachable", true}, + {"effect", "none"}}}, + {"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, + {"type", "Extended color light"}, {"name", "Hue lamp 3"}, {"modelid", "LCT010"}, + {"manufacturername", "Philips"}, {"productname", "Hue bloom"}, + {"swversion", "5.50.1.19085"}}}}}}), test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler) { using namespace ::testing; - hue_bridge_state["lights"] = nlohmann::json::object(); - hue_bridge_state["lights"]["1"] = nlohmann::json::object(); - hue_bridge_state["lights"]["1"]["state"] = nlohmann::json::object(); - hue_bridge_state["lights"]["1"]["state"]["on"] = true; - hue_bridge_state["lights"]["1"]["state"]["bri"] = 254; - hue_bridge_state["lights"]["1"]["state"]["ct"] = 366; - hue_bridge_state["lights"]["1"]["state"]["alert"] = "none"; - hue_bridge_state["lights"]["1"]["state"]["colormode"] = "ct"; - hue_bridge_state["lights"]["1"]["state"]["reachable"] = true; - hue_bridge_state["lights"]["1"]["state"]["effect"] = "none"; - hue_bridge_state["lights"]["1"]["swupdate"] = nlohmann::json::object(); - hue_bridge_state["lights"]["1"]["swupdate"]["state"] = "noupdates"; - hue_bridge_state["lights"]["1"]["swupdate"]["lastinstall"] = nullptr; - hue_bridge_state["lights"]["1"]["type"] = "Dimmable light"; - hue_bridge_state["lights"]["1"]["name"] = "Hue lamp 1"; - hue_bridge_state["lights"]["1"]["modelid"] = "LWB004"; - hue_bridge_state["lights"]["1"]["manufacturername"] = "Philips"; - hue_bridge_state["lights"]["1"]["productname"] = "Hue bloom"; - hue_bridge_state["lights"]["1"]["uniqueid"] = "00:00:00:00:00:00:00:00-00"; - hue_bridge_state["lights"]["1"]["swversion"] = "5.50.1.19085"; - hue_bridge_state["lights"]["1"]["luminaireuniqueid"] = "0000000"; - hue_bridge_state["lights"]["2"] = nlohmann::json::object(); - hue_bridge_state["lights"]["2"]["state"] = nlohmann::json::object(); - hue_bridge_state["lights"]["2"]["state"]["on"] = false; - hue_bridge_state["lights"]["2"]["state"]["bri"] = 0; - hue_bridge_state["lights"]["2"]["state"]["ct"] = 366; - hue_bridge_state["lights"]["2"]["state"]["hue"] = 123456; - hue_bridge_state["lights"]["2"]["state"]["sat"] = 123; - hue_bridge_state["lights"]["2"]["state"]["xy"][0] = 0.102; - hue_bridge_state["lights"]["2"]["state"]["xy"][1] = 0.102; - hue_bridge_state["lights"]["2"]["state"]["alert"] = "none"; - hue_bridge_state["lights"]["2"]["state"]["colormode"] = "ct"; - hue_bridge_state["lights"]["2"]["state"]["reachable"] = true; - hue_bridge_state["lights"]["2"]["state"]["effect"] = "none"; - hue_bridge_state["lights"]["2"]["swupdate"] = nlohmann::json::object(); - hue_bridge_state["lights"]["2"]["swupdate"]["state"] = "noupdates"; - hue_bridge_state["lights"]["2"]["swupdate"]["lastinstall"] = nullptr; - hue_bridge_state["lights"]["2"]["type"] = "Color light"; - hue_bridge_state["lights"]["2"]["name"] = "Hue lamp 2"; - hue_bridge_state["lights"]["2"]["modelid"] = "LST001"; - hue_bridge_state["lights"]["2"]["uniqueid"] = "11:11:11:11:11:11:11:11-11"; - hue_bridge_state["lights"]["2"]["swversion"] = "5.50.1.19085"; - hue_bridge_state["lights"]["3"] = nlohmann::json::object(); - hue_bridge_state["lights"]["3"]["state"] = nlohmann::json::object(); - hue_bridge_state["lights"]["3"]["state"]["on"] = false; - hue_bridge_state["lights"]["3"]["state"]["bri"] = 254; - hue_bridge_state["lights"]["3"]["state"]["ct"] = 366; - hue_bridge_state["lights"]["3"]["state"]["hue"] = 123456; - hue_bridge_state["lights"]["3"]["state"]["sat"] = 123; - hue_bridge_state["lights"]["3"]["state"]["xy"][0] = 0.102; - hue_bridge_state["lights"]["3"]["state"]["xy"][1] = 0.102; - hue_bridge_state["lights"]["3"]["state"]["alert"] = "none"; - hue_bridge_state["lights"]["3"]["state"]["colormode"] = "ct"; - hue_bridge_state["lights"]["3"]["state"]["reachable"] = true; - hue_bridge_state["lights"]["3"]["state"]["effect"] = "none"; - hue_bridge_state["lights"]["3"]["swupdate"] = nlohmann::json::object(); - hue_bridge_state["lights"]["3"]["swupdate"]["state"] = "noupdates"; - hue_bridge_state["lights"]["3"]["swupdate"]["lastinstall"] = nullptr; - hue_bridge_state["lights"]["3"]["type"] = "Extended color light"; - hue_bridge_state["lights"]["3"]["name"] = "Hue lamp 3"; - hue_bridge_state["lights"]["3"]["modelid"] = "LCT010"; - hue_bridge_state["lights"]["3"]["manufacturername"] = "Philips"; - hue_bridge_state["lights"]["3"]["productname"] = "Hue bloom"; - hue_bridge_state["lights"]["3"]["swversion"] = "5.50.1.19085"; EXPECT_CALL(*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), 80)) .Times(AtLeast(1)) @@ -126,7 +88,7 @@ protected: .Times(AtLeast(1)) .WillRepeatedly(Return(hue_bridge_state["lights"]["3"])); } - ~HueLightTest(){}; + ~HueLightTest() {}; }; TEST_F(HueLightTest, Constructor) @@ -692,15 +654,15 @@ TEST_F(HueLightTest, getColorHueSaturation) HueLight test_light_3 = test_bridge.getLight(3); EXPECT_EQ(std::make_pair(static_cast(0), static_cast(0)), ctest_light_1.getColorHueSaturation()); - EXPECT_EQ(std::make_pair(static_cast(123456), static_cast(123)), - ctest_light_2.getColorHueSaturation()); - EXPECT_EQ(std::make_pair(static_cast(123456), static_cast(123)), - ctest_light_3.getColorHueSaturation()); + EXPECT_EQ( + std::make_pair(static_cast(12345), static_cast(123)), ctest_light_2.getColorHueSaturation()); + EXPECT_EQ( + std::make_pair(static_cast(12345), static_cast(123)), ctest_light_3.getColorHueSaturation()); EXPECT_EQ(std::make_pair(static_cast(0), static_cast(0)), test_light_1.getColorHueSaturation()); EXPECT_EQ( - std::make_pair(static_cast(123456), static_cast(123)), test_light_2.getColorHueSaturation()); + std::make_pair(static_cast(12345), static_cast(123)), test_light_2.getColorHueSaturation()); EXPECT_EQ( - std::make_pair(static_cast(123456), static_cast(123)), test_light_3.getColorHueSaturation()); + std::make_pair(static_cast(12345), static_cast(123)), test_light_3.getColorHueSaturation()); } TEST_F(HueLightTest, setColorXY) diff --git a/test/test_Main.cpp b/test/test_Main.cpp index a51d328..98526bb 100644 --- a/test/test_Main.cpp +++ b/test/test_Main.cpp @@ -21,9 +21,35 @@ **/ #include +#include + +namespace +{ +class TestConfig : public hueplusplus::Config +{ +public: + TestConfig() + { + preAlertDelay = postAlertDelay = upnpTimeout = bridgeRequestDelay = requestUsernameDelay + = requestUsernameAttemptInterval = std::chrono::seconds(0); + } +}; + +// Environment sets config to disable all delays and speed up tests +class Environment : public ::testing::Environment +{ +public: + ~Environment() override {} + + void SetUp() override { hueplusplus::Config::instance() = TestConfig(); } + + void TearDown() override {} +}; +} // namespace int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new Environment()); return RUN_ALL_TESTS(); } diff --git a/test/test_UPnP.cpp b/test/test_UPnP.cpp index f001d80..17f5feb 100644 --- a/test/test_UPnP.cpp +++ b/test/test_UPnP.cpp @@ -26,6 +26,7 @@ #include "iostream" #include "testhelper.h" +#include "hueplusplus/HueConfig.h" #include "hueplusplus/UPnP.h" #include "json/json.hpp" #include "mocks/mock_HttpHandler.h" @@ -42,7 +43,7 @@ TEST(UPnP, getDevices) EXPECT_CALL(*handler, sendMulticast("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: " "\"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n", - "239.255.255.250", 1900, 5)) + "239.255.255.250", 1900, Config::instance().getUPnPTimeout())) .Times(1) .WillRepeatedly(::testing::Return(getMulticastReply()));