Commit ab6b127803cb884c5532bf2670516aab208a12f7

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent 654ab503

Add Config singleton which allows to change the delays.

Setting all delays to zero significantly speeds up test times.
include/hueplusplus/Hue.h
... ... @@ -360,7 +360,6 @@ private:
360 360  
361 361 std::shared_ptr<const IHttpHandler> http_handler; //!< A IHttpHandler that is used to communicate with the
362 362 //!< bridge
363   - std::chrono::steady_clock::duration refreshDuration;
364 363  
365 364 std::shared_ptr<APICache> stateCache;
366 365 ResourceList<HueLight, int> lights;
... ...
include/hueplusplus/HueCommandAPI.h
... ... @@ -135,9 +135,6 @@ private:
135 135 //! \returns "/api/<username>/<path>"
136 136 std::string CombinedPath(const std::string& path) const;
137 137  
138   -public:
139   - static constexpr std::chrono::steady_clock::duration minDelay = std::chrono::milliseconds(100);
140   -
141 138 private:
142 139 std::string ip;
143 140 int port;
... ...
include/hueplusplus/HueConfig.h
... ... @@ -23,10 +23,53 @@
23 23 #ifndef INCLUDE_HUEPLUSPLUS_HUE_CONFIG_H
24 24 #define INCLUDE_HUEPLUSPLUS_HUE_CONFIG_H
25 25  
  26 +#include <chrono>
  27 +
26 28 namespace hueplusplus
27 29 {
28   -constexpr uint16_t c_PRE_ALERT_DELAY = 120; //!< Delay for advanced alerts before the actual alert
29   -constexpr uint16_t c_POST_ALERT_DELAY = 1600; //!< Delay for advanced alerts after the actual alert
  30 +//! \brief Configurable delays
  31 +//!
  32 +//! Used to set all delays to zero when running tests.
  33 +class Config
  34 +{
  35 +private:
  36 + using duration = std::chrono::steady_clock::duration;
  37 +
  38 +public:
  39 + //! \brief Delay for advanced alerts before the actual alert
  40 + duration getPreAlertDelay() const { return preAlertDelay; }
  41 + //! \brief Delay for advanced alerts after the actual alert
  42 + duration getPostAlertDelay() const { return postAlertDelay; }
  43 +
  44 + //! \brief Timeout for UPnP multicast request
  45 + duration getUPnPTimeout() const { return upnpTimeout; }
  46 +
  47 + //! \brief Delay between bridge requests
  48 + duration getBridgeRequestDelay() const { return bridgeRequestDelay; }
  49 +
  50 + //! \brief Timeout for Hue::requestUsername, waits until link button was pressed
  51 + duration getRequestUsernameTimeout() const { return requestUsernameDelay; }
  52 +
  53 + //! \brief Interval in which username requests are attempted
  54 + duration getRequestUsernameAttemptInterval() const { return requestUsernameAttemptInterval; }
  55 +
  56 + //! \brief Get config instance
  57 + static Config& instance()
  58 + {
  59 + static Config c;
  60 + return c;
  61 + }
  62 +protected:
  63 + Config() = default;
  64 +
  65 +protected:
  66 + duration preAlertDelay = std::chrono::milliseconds(120);
  67 + duration postAlertDelay = std::chrono::milliseconds(1600);
  68 + duration upnpTimeout = std::chrono::seconds(5);
  69 + duration bridgeRequestDelay = std::chrono::milliseconds(100);
  70 + duration requestUsernameDelay = std::chrono::seconds(35);
  71 + duration requestUsernameAttemptInterval = std::chrono::seconds(1);
  72 +};
30 73 } // namespace hueplusplus
31 74  
32 75 #endif
... ...
include/hueplusplus/IHttpHandler.h
... ... @@ -23,6 +23,7 @@
23 23 #ifndef INCLUDE_HUEPLUSPLUS_IHTTPHANDLER_H
24 24 #define INCLUDE_HUEPLUSPLUS_IHTTPHANDLER_H
25 25  
  26 +#include <chrono>
26 27 #include <iostream>
27 28 #include <memory>
28 29 #include <string>
... ... @@ -63,14 +64,14 @@ public:
63 64 //! \param msg The message that should sent to the specified multicast address
64 65 //! \param adr Optional ip or hostname in dotted decimal notation, default is "239.255.255.250"
65 66 //! \param port Optional port the request is sent to, default is 1900
66   - //! \param timeout Optional time to wait for responses in seconds, default is 5
  67 + //! \param timeout Optional time to wait for responses, default is 5 seconds
67 68 //!
68 69 //! Blocks for the duration of the timeout.
69 70 //!
70 71 //! \return vector of strings containing each received answer
71 72 //! \throws std::system_error when system or socket operations fail
72   - virtual std::vector<std::string> sendMulticast(
73   - const std::string& msg, const std::string& adr = "239.255.255.250", int port = 1900, int timeout = 5) const = 0;
  73 + virtual std::vector<std::string> sendMulticast(const std::string& msg, const std::string& adr = "239.255.255.250",
  74 + int port = 1900, std::chrono::steady_clock::duration timeout = std::chrono::seconds(5)) const = 0;
74 75  
75 76 //! \brief Send a HTTP request with the given method to the specified host and return the body of the response.
76 77 //!
... ...
include/hueplusplus/LinHttpHandler.h
... ... @@ -52,11 +52,11 @@ public:
52 52 //! address \param adr Optional String that contains an ip or hostname in
53 53 //! dotted decimal notation, default is "239.255.255.250" \param port Optional
54 54 //! integer that specifies the port to which the request is sent. Default is
55   - //! 1900 \param timeout Optional Integer that specifies the timeout of the
56   - //! request in seconds. Default is 5 \return Vector containing strings of each
  55 + //! 1900 \param timeout Optional The timeout of the
  56 + //! request. Default is 5 seconds \return Vector containing strings of each
57 57 //! answer received
58   - virtual std::vector<std::string> sendMulticast(
59   - const std::string& msg, const std::string& adr = "239.255.255.250", int port = 1900, int timeout = 5) const;
  58 + std::vector<std::string> sendMulticast(const std::string& msg, const std::string& adr = "239.255.255.250",
  59 + int port = 1900, std::chrono::steady_clock::duration timeout = std::chrono::seconds(5)) const override;
60 60 };
61 61 } // namespace hueplusplus
62 62  
... ...
include/hueplusplus/WinHttpHandler.h
... ... @@ -58,11 +58,11 @@ public:
58 58 //! address \param adr Optional String that contains an ip or hostname in
59 59 //! dotted decimal notation, default is "239.255.255.250" \param port Optional
60 60 //! integer that specifies the port to which the request is sent. Default is
61   - //! 1900 \param timeout Optional Integer that specifies the timeout of the
62   - //! request in seconds. Default is 5 \return Vector containing strings of each
  61 + //! 1900 \param timeout Optional The timeout of the
  62 + //! request. Default is 5 seconds \return Vector containing strings of each
63 63 //! answer received
64 64 std::vector<std::string> sendMulticast(const std::string& msg, const std::string& adr = "239.255.255.250",
65   - int port = 1900, int timeout = 5) const override;
  65 + int port = 1900, std::chrono::steady_clock::duration timeout = std::chrono::seconds(5)) const override;
66 66  
67 67 private:
68 68 WSADATA wsaData;
... ...
src/ExtendedColorHueStrategy.cpp
... ... @@ -44,12 +44,12 @@ bool ExtendedColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, Hue
44 44 {
45 45 return false;
46 46 }
47   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  47 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
48 48 if (!light.alert())
49 49 {
50 50 return false;
51 51 }
52   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  52 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
53 53 if (!on)
54 54 {
55 55 light.setColorHueSaturation(oldHue, oldSat, 1);
... ... @@ -68,12 +68,12 @@ bool ExtendedColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, Hue
68 68 {
69 69 return false;
70 70 }
71   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  71 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
72 72 if (!light.alert())
73 73 {
74 74 return false;
75 75 }
76   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  76 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
77 77 if (!on)
78 78 {
79 79 light.setColorXY(oldX, oldY, 1);
... ... @@ -91,12 +91,12 @@ bool ExtendedColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, Hue
91 91 {
92 92 return false;
93 93 }
94   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  94 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
95 95 if (!light.alert())
96 96 {
97 97 return false;
98 98 }
99   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  99 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
100 100 if (!on)
101 101 {
102 102 light.setColorTemperature(oldCT, 1);
... ... @@ -127,12 +127,12 @@ bool ExtendedColorHueStrategy::alertXY(float x, float y, HueLight&amp; light) const
127 127 {
128 128 return false;
129 129 }
130   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  130 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
131 131 if (!light.alert())
132 132 {
133 133 return false;
134 134 }
135   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  135 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
136 136 if (!on)
137 137 {
138 138 light.setColorHueSaturation(oldHue, oldSat, 1);
... ... @@ -151,12 +151,12 @@ bool ExtendedColorHueStrategy::alertXY(float x, float y, HueLight&amp; light) const
151 151 {
152 152 return false;
153 153 }
154   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  154 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
155 155 if (!light.alert())
156 156 {
157 157 return false;
158 158 }
159   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  159 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
160 160 if (!on)
161 161 {
162 162 light.setColorXY(oldX, oldY, 1);
... ... @@ -174,12 +174,12 @@ bool ExtendedColorHueStrategy::alertXY(float x, float y, HueLight&amp; light) const
174 174 {
175 175 return false;
176 176 }
177   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  177 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
178 178 if (!light.alert())
179 179 {
180 180 return false;
181 181 }
182   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  182 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
183 183 if (!on)
184 184 {
185 185 light.setColorTemperature(oldCT, 1);
... ... @@ -210,12 +210,12 @@ bool ExtendedColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLigh
210 210 {
211 211 return false;
212 212 }
213   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  213 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
214 214 if (!light.alert())
215 215 {
216 216 return false;
217 217 }
218   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  218 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
219 219 if (!on)
220 220 {
221 221 light.setColorHueSaturation(oldHue, oldSat, 1);
... ... @@ -234,12 +234,12 @@ bool ExtendedColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLigh
234 234 {
235 235 return false;
236 236 }
237   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  237 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
238 238 if (!light.alert())
239 239 {
240 240 return false;
241 241 }
242   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  242 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
243 243 if (!on)
244 244 {
245 245 light.setColorXY(oldX, oldY, 1);
... ... @@ -257,12 +257,12 @@ bool ExtendedColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLigh
257 257 {
258 258 return false;
259 259 }
260   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  260 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
261 261 if (!light.alert())
262 262 {
263 263 return false;
264 264 }
265   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  265 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
266 266 if (!on)
267 267 {
268 268 light.setColorTemperature(oldCT, 1);
... ...
src/ExtendedColorTemperatureStrategy.cpp
... ... @@ -85,12 +85,12 @@ bool ExtendedColorTemperatureStrategy::alertTemperature(unsigned int mired, HueL
85 85 {
86 86 return false;
87 87 }
88   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  88 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
89 89 if (!light.alert())
90 90 {
91 91 return false;
92 92 }
93   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  93 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
94 94 if (!on)
95 95 {
96 96 light.setColorHueSaturation(oldHue, oldSat, 1);
... ... @@ -109,12 +109,12 @@ bool ExtendedColorTemperatureStrategy::alertTemperature(unsigned int mired, HueL
109 109 {
110 110 return false;
111 111 }
112   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  112 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
113 113 if (!light.alert())
114 114 {
115 115 return false;
116 116 }
117   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  117 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
118 118 if (!on)
119 119 {
120 120 light.setColorXY(oldX, oldY, 1);
... ... @@ -132,12 +132,12 @@ bool ExtendedColorTemperatureStrategy::alertTemperature(unsigned int mired, HueL
132 132 {
133 133 return false;
134 134 }
135   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  135 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
136 136 if (!light.alert())
137 137 {
138 138 return false;
139 139 }
140   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  140 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
141 141 if (!on)
142 142 {
143 143 light.setColorTemperature(oldCT, 1);
... ...
src/Hue.cpp
... ... @@ -31,6 +31,7 @@
31 31 #include <stdexcept>
32 32 #include <thread>
33 33  
  34 +#include "hueplusplus/HueConfig.h"
34 35 #include "hueplusplus/HueExceptionMacro.h"
35 36 #include "hueplusplus/UPnP.h"
36 37 #include "hueplusplus/Utils.h"
... ... @@ -160,51 +161,44 @@ int Hue::getBridgePort() const
160 161  
161 162 std::string Hue::requestUsername()
162 163 {
163   - std::cout << "Please press the link Button! You've got 35 secs!\n"; // when the link
164   - // button was
165   - // pressed we
166   - // got 30
167   - // seconds to
168   - // get our
169   - // username for
170   - // control
  164 + std::chrono::steady_clock::duration timeout = Config::instance().getRequestUsernameTimeout();
  165 + std::chrono::steady_clock::duration checkInterval = Config::instance().getRequestUsernameAttemptInterval();
  166 + std::cout << "Please press the link Button! You've got "
  167 + << std::chrono::duration_cast<std::chrono::seconds>(timeout).count() << " secs!\n";
171 168  
  169 + // when the link button was pressed we got 30 seconds to get our username for control
172 170 nlohmann::json request;
173 171 request["devicetype"] = "HuePlusPlus#User";
174 172  
175 173 nlohmann::json answer;
176 174 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
177   - std::chrono::steady_clock::time_point lastCheck;
178   - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(35))
  175 + // do-while loop to check at least once when timeout is 0
  176 + do
179 177 {
180   - if (std::chrono::steady_clock::now() - lastCheck > std::chrono::seconds(1))
  178 + std::this_thread::sleep_for(checkInterval);
  179 + answer = http_handler->POSTJson("/api", request, ip, port);
  180 + nlohmann::json jsonUser = utils::safeGetMember(answer, 0, "success", "username");
  181 + if (jsonUser != nullptr)
181 182 {
182   - lastCheck = std::chrono::steady_clock::now();
183   - answer = http_handler->POSTJson("/api", request, ip, port);
184   - nlohmann::json jsonUser = utils::safeGetMember(answer, 0, "success", "username");
185   - if (jsonUser != nullptr)
186   - {
187   - // [{"success":{"username": "<username>"}}]
188   - username = jsonUser.get<std::string>();
189   - // Update commands with new username and ip
190   - setHttpHandler(http_handler);
191   - std::cout << "Success! Link button was pressed!\n";
192   - std::cout << "Username is \"" << username << "\"\n";
193   - break;
194   - }
195   - else if (answer.size() > 0 && answer[0].count("error"))
  183 + // [{"success":{"username": "<username>"}}]
  184 + username = jsonUser.get<std::string>();
  185 + // Update commands with new username and ip
  186 + setHttpHandler(http_handler);
  187 + std::cout << "Success! Link button was pressed!\n";
  188 + std::cout << "Username is \"" << username << "\"\n";
  189 + break;
  190 + }
  191 + else if (answer.size() > 0 && answer[0].count("error"))
  192 + {
  193 + HueAPIResponseException exception = HueAPIResponseException::Create(CURRENT_FILE_INFO, answer[0]);
  194 + // All errors except 101: Link button not pressed
  195 + if (exception.GetErrorNumber() != 101)
196 196 {
197   - HueAPIResponseException exception = HueAPIResponseException::Create(CURRENT_FILE_INFO, answer[0]);
198   - // All errors except 101: Link button not pressed
199   - if (exception.GetErrorNumber() != 101)
200   - {
201   - throw exception;
202   - }
  197 + throw exception;
203 198 }
204   -
205   - std::this_thread::sleep_until(lastCheck + std::chrono::seconds(1));
206 199 }
207   - }
  200 + } while (std::chrono::steady_clock::now() - start < timeout);
  201 +
208 202 return username;
209 203 }
210 204  
... ... @@ -425,9 +419,10 @@ std::string Hue::getPictureOfModel(const std::string&amp; model_id) const
425 419 void Hue::setHttpHandler(std::shared_ptr<const IHttpHandler> handler)
426 420 {
427 421 http_handler = handler;
428   - stateCache = std::make_shared<APICache>("", HueCommandAPI(ip, port, username, handler), refreshDuration);
  422 + stateCache
  423 + = std::make_shared<APICache>("", HueCommandAPI(ip, port, username, handler), stateCache->getRefreshDuration());
429 424 lights = ResourceList<HueLight, int>("/lights", stateCache, "lights",
430   - [factory = HueLightFactory(stateCache->getCommandAPI(), refreshDuration)](
  425 + [factory = HueLightFactory(stateCache->getCommandAPI(), stateCache->getRefreshDuration())](
431 426 int id, const nlohmann::json& state) mutable { return factory.createLight(state, id); });
432 427 groups = CreateableResourceList<Group, int, CreateGroup>("/groups", stateCache, "groups");
433 428 schedules = CreateableResourceList<Schedule, int, CreateSchedule>("/schedules", stateCache, "schedules");
... ...
src/HueCommandAPI.cpp
... ... @@ -24,12 +24,11 @@
24 24  
25 25 #include <thread>
26 26  
  27 +#include "hueplusplus/HueConfig.h"
27 28 #include "hueplusplus/HueExceptionMacro.h"
28 29  
29 30 namespace hueplusplus
30 31 {
31   -constexpr std::chrono::steady_clock::duration HueCommandAPI::minDelay;
32   -
33 32 namespace
34 33 {
35 34 // Runs functor with appropriate timeout and retries when timed out or connection reset
... ... @@ -81,7 +80,7 @@ nlohmann::json HueCommandAPI::PUTRequest(const std::string&amp; path, const nlohmann
81 80 nlohmann::json HueCommandAPI::PUTRequest(
82 81 const std::string& path, const nlohmann::json& request, FileInfo fileInfo) const
83 82 {
84   - return HandleError(std::move(fileInfo), RunWithTimeout(timeout, minDelay, [&]() {
  83 + return HandleError(std::move(fileInfo), RunWithTimeout(timeout, Config::instance().getBridgeRequestDelay(), [&]() {
85 84 return httpHandler->PUTJson(CombinedPath(path), request, ip, port);
86 85 }));
87 86 }
... ... @@ -94,7 +93,7 @@ nlohmann::json HueCommandAPI::GETRequest(const std::string&amp; path, const nlohmann
94 93 nlohmann::json HueCommandAPI::GETRequest(
95 94 const std::string& path, const nlohmann::json& request, FileInfo fileInfo) const
96 95 {
97   - return HandleError(std::move(fileInfo), RunWithTimeout(timeout, minDelay, [&]() {
  96 + return HandleError(std::move(fileInfo), RunWithTimeout(timeout, Config::instance().getBridgeRequestDelay(), [&]() {
98 97 return httpHandler->GETJson(CombinedPath(path), request, ip, port);
99 98 }));
100 99 }
... ... @@ -107,7 +106,7 @@ nlohmann::json HueCommandAPI::DELETERequest(const std::string&amp; path, const nlohm
107 106 nlohmann::json HueCommandAPI::DELETERequest(
108 107 const std::string& path, const nlohmann::json& request, FileInfo fileInfo) const
109 108 {
110   - return HandleError(std::move(fileInfo), RunWithTimeout(timeout, minDelay, [&]() {
  109 + return HandleError(std::move(fileInfo), RunWithTimeout(timeout, Config::instance().getBridgeRequestDelay(), [&]() {
111 110 return httpHandler->DELETEJson(CombinedPath(path), request, ip, port);
112 111 }));
113 112 }
... ... @@ -120,7 +119,7 @@ nlohmann::json HueCommandAPI::POSTRequest(const std::string&amp; path, const nlohman
120 119 nlohmann::json HueCommandAPI::POSTRequest(
121 120 const std::string& path, const nlohmann::json& request, FileInfo fileInfo) const
122 121 {
123   - return HandleError(std::move(fileInfo), RunWithTimeout(timeout, minDelay, [&]() {
  122 + return HandleError(std::move(fileInfo), RunWithTimeout(timeout, Config::instance().getBridgeRequestDelay(), [&]() {
124 123 return httpHandler->POSTJson(CombinedPath(path), request, ip, port);
125 124 }));
126 125 }
... ...
src/LinHttpHandler.cpp
... ... @@ -139,7 +139,7 @@ std::string LinHttpHandler::send(const std::string&amp; msg, const std::string&amp; adr,
139 139 }
140 140  
141 141 std::vector<std::string> LinHttpHandler::sendMulticast(
142   - const std::string& msg, const std::string& adr, int port, int timeout) const
  142 + const std::string& msg, const std::string& adr, int port, std::chrono::steady_clock::duration timeout) const
143 143 {
144 144 hostent* server; // host information
145 145 sockaddr_in server_addr; // server address
... ... @@ -187,7 +187,7 @@ std::vector&lt;std::string&gt; LinHttpHandler::sendMulticast(
187 187 char buffer[2048] = {}; // receive buffer
188 188  
189 189 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
190   - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout))
  190 + while (std::chrono::steady_clock::now() - start < timeout)
191 191 {
192 192 ssize_t bytesReceived = recv(socketFD, &buffer, 2048, MSG_DONTWAIT);
193 193 if (bytesReceived < 0)
... ...
src/SimpleColorHueStrategy.cpp
... ... @@ -97,12 +97,12 @@ bool SimpleColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, HueLi
97 97 {
98 98 return false;
99 99 }
100   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  100 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
101 101 if (!light.alert())
102 102 {
103 103 return false;
104 104 }
105   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  105 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
106 106 if (!on)
107 107 {
108 108 light.setColorHueSaturation(oldHue, oldSat, 1);
... ... @@ -121,12 +121,12 @@ bool SimpleColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, HueLi
121 121 {
122 122 return false;
123 123 }
124   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  124 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
125 125 if (!light.alert())
126 126 {
127 127 return false;
128 128 }
129   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  129 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
130 130 if (!on)
131 131 {
132 132 light.setColorXY(oldX, oldY, 1);
... ... @@ -157,12 +157,12 @@ bool SimpleColorHueStrategy::alertXY(float x, float y, HueLight&amp; light) const
157 157 {
158 158 return false;
159 159 }
160   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  160 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
161 161 if (!light.alert())
162 162 {
163 163 return false;
164 164 }
165   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  165 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
166 166 if (!on)
167 167 {
168 168 light.setColorHueSaturation(oldHue, oldSat, 1);
... ... @@ -181,12 +181,12 @@ bool SimpleColorHueStrategy::alertXY(float x, float y, HueLight&amp; light) const
181 181 {
182 182 return false;
183 183 }
184   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  184 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
185 185 if (!light.alert())
186 186 {
187 187 return false;
188 188 }
189   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  189 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
190 190 if (!on)
191 191 {
192 192 light.setColorXY(oldX, oldY, 1);
... ... @@ -217,12 +217,12 @@ bool SimpleColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLight&amp;
217 217 {
218 218 return false;
219 219 }
220   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  220 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
221 221 if (!light.alert())
222 222 {
223 223 return false;
224 224 }
225   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  225 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
226 226 if (!on)
227 227 {
228 228 light.setColorHueSaturation(oldHue, oldSat, 1);
... ... @@ -241,12 +241,12 @@ bool SimpleColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLight&amp;
241 241 {
242 242 return false;
243 243 }
244   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  244 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
245 245 if (!light.alert())
246 246 {
247 247 return false;
248 248 }
249   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  249 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
250 250 if (!on)
251 251 {
252 252 light.setColorXY(oldX, oldY, 1);
... ...
src/SimpleColorTemperatureStrategy.cpp
... ... @@ -50,12 +50,12 @@ bool SimpleColorTemperatureStrategy::alertTemperature(unsigned int mired, HueLig
50 50 {
51 51 return false;
52 52 }
53   - std::this_thread::sleep_for(std::chrono::milliseconds(c_PRE_ALERT_DELAY));
  53 + std::this_thread::sleep_for(Config::instance().getPreAlertDelay());
54 54 if (!light.alert())
55 55 {
56 56 return false;
57 57 }
58   - std::this_thread::sleep_for(std::chrono::milliseconds(c_POST_ALERT_DELAY));
  58 + std::this_thread::sleep_for(Config::instance().getPostAlertDelay());
59 59 if (!on)
60 60 {
61 61 light.setColorTemperature(oldCT, 1);
... ...
src/UPnP.cpp
... ... @@ -25,6 +25,8 @@
25 25 #include <algorithm>
26 26 #include <iostream>
27 27  
  28 +#include "hueplusplus/HueConfig.h"
  29 +
28 30 namespace hueplusplus
29 31 {
30 32 std::vector<std::pair<std::string, std::string>> UPnP::getDevices(std::shared_ptr<const IHttpHandler> handler)
... ... @@ -33,7 +35,7 @@ std::vector&lt;std::pair&lt;std::string, std::string&gt;&gt; UPnP::getDevices(std::shared_pt
33 35 std::vector<std::string> foundDevices
34 36 = handler->sendMulticast("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: "
35 37 "\"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n",
36   - "239.255.255.250", 1900, 5);
  38 + "239.255.255.250", 1900, Config::instance().getUPnPTimeout());
37 39  
38 40 std::vector<std::pair<std::string, std::string>> devices;
39 41  
... ... @@ -41,9 +43,19 @@ std::vector&lt;std::pair&lt;std::string, std::string&gt;&gt; UPnP::getDevices(std::shared_pt
41 43 for (const std::string& s : foundDevices)
42 44 {
43 45 std::pair<std::string, std::string> device;
44   - int start = s.find("LOCATION:") + 10;
  46 + std::size_t start = s.find("LOCATION:");
  47 + if (start == std::string::npos)
  48 + {
  49 + continue;
  50 + }
  51 + start += 10;
45 52 device.first = s.substr(start, s.find("\r\n", start) - start);
46   - start = s.find("SERVER:") + 8;
  53 + start = s.find("SERVER:");
  54 + if (start == std::string::npos)
  55 + {
  56 + continue;
  57 + }
  58 + start += 8;
47 59 device.second = s.substr(start, s.find("\r\n", start) - start);
48 60 if (std::find_if(devices.begin(), devices.end(),
49 61 [&](const std::pair<std::string, std::string>& item) { return item.first == device.first; })
... ...
src/WinHttpHandler.cpp
... ... @@ -174,7 +174,7 @@ std::string WinHttpHandler::send(const std::string&amp; msg, const std::string&amp; adr,
174 174 }
175 175  
176 176 std::vector<std::string> WinHttpHandler::sendMulticast(
177   - const std::string& msg, const std::string& adr, int port, int timeout) const
  177 + const std::string& msg, const std::string& adr, int port, std::chrono::steady_clock::duration timeout) const
178 178 {
179 179 struct addrinfo hints = {};
180 180 hints.ai_family = AF_INET;
... ... @@ -262,7 +262,7 @@ std::vector&lt;std::string&gt; WinHttpHandler::sendMulticast(
262 262 const int recvbuflen = 2048;
263 263 char recvbuf[recvbuflen] = {};
264 264 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
265   - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout))
  265 + while (std::chrono::steady_clock::now() - start < timeout)
266 266 {
267 267 int res = recv(connect_socket, recvbuf, recvbuflen, 0);
268 268 if (res > 0)
... ...
test/mocks/mock_BaseHttpHandler.h
... ... @@ -38,7 +38,7 @@ public:
38 38 MOCK_CONST_METHOD3(send, std::string(const std::string& msg, const std::string& adr, int port));
39 39  
40 40 MOCK_CONST_METHOD4(
41   - sendMulticast, std::vector<std::string>(const std::string& msg, const std::string& adr, int port, int timeout));
  41 + sendMulticast, std::vector<std::string>(const std::string& msg, const std::string& adr, int port, std::chrono::steady_clock::duration timeout));
42 42 };
43 43  
44 44 #endif
... ...
test/mocks/mock_HttpHandler.h
... ... @@ -39,8 +39,9 @@ public:
39 39  
40 40 MOCK_CONST_METHOD3(sendGetHTTPBody, std::string(const std::string& msg, const std::string& adr, int port));
41 41  
42   - MOCK_CONST_METHOD4(
43   - sendMulticast, std::vector<std::string>(const std::string& msg, const std::string& adr, int port, int timeout));
  42 + MOCK_CONST_METHOD4(sendMulticast,
  43 + std::vector<std::string>(
  44 + const std::string& msg, const std::string& adr, int port, std::chrono::steady_clock::duration timeout));
44 45  
45 46 MOCK_CONST_METHOD6(sendHTTPRequest,
46 47 std::string(const std::string& method, const std::string& uri, const std::string& content_type,
... ...
test/test_Hue.cpp
... ... @@ -29,6 +29,7 @@
29 29 #include "testhelper.h"
30 30  
31 31 #include "hueplusplus/Hue.h"
  32 +#include "hueplusplus/HueConfig.h"
32 33 #include "json/json.hpp"
33 34 #include "mocks/mock_HttpHandler.h"
34 35  
... ... @@ -47,7 +48,7 @@ protected:
47 48 EXPECT_CALL(*handler,
48 49 sendMulticast("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: "
49 50 "\"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n",
50   - "239.255.255.250", 1900, 5))
  51 + "239.255.255.250", 1900, Config::instance().getUPnPTimeout()))
51 52 .Times(AtLeast(1))
52 53 .WillRepeatedly(Return(getMulticastReply()));
53 54  
... ...
test/test_HueLight.cpp
... ... @@ -42,73 +42,35 @@ protected:
42 42 protected:
43 43 HueLightTest()
44 44 : handler(std::make_shared<MockHttpHandler>()),
  45 + hue_bridge_state({{"lights",
  46 + {{"1",
  47 + {{"state",
  48 + {{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"},
  49 + {"reachable", true}, {"effect", "none"}}},
  50 + {"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Dimmable light"},
  51 + {"name", "Hue lamp 1"}, {"modelid", "LWB004"}, {"manufacturername", "Philips"},
  52 + {"productname", "Hue bloom"}, {"uniqueid", "00:00:00:00:00:00:00:00-00"},
  53 + {"swversion", "5.50.1.19085"}, {"luminaireuniqueid", "0000000"}}},
  54 + {"2",
  55 + {{"state",
  56 + {{"on", false}, {"bri", 0}, {"ct", 366}, {"hue", 12345}, {"sat", 123},
  57 + {"xy", {0.102, 0.102}}, {"alert", "none"}, {"colormode", "ct"}, {"reachable", true},
  58 + {"effect", "none"}}},
  59 + {"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color light"},
  60 + {"name", "Hue lamp 2"}, {"modelid", "LST001"}, {"uniqueid", "11:11:11:11:11:11:11:11-11"},
  61 + {"swversion", "5.50.1.19085"}}},
  62 + {"3",
  63 + {{"state",
  64 + {{"on", false}, {"bri", 254}, {"ct", 366}, {"hue", 12345}, {"sat", 123},
  65 + {"xy", {0.102, 0.102}}, {"alert", "none"}, {"colormode", "ct"}, {"reachable", true},
  66 + {"effect", "none"}}},
  67 + {"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}},
  68 + {"type", "Extended color light"}, {"name", "Hue lamp 3"}, {"modelid", "LCT010"},
  69 + {"manufacturername", "Philips"}, {"productname", "Hue bloom"},
  70 + {"swversion", "5.50.1.19085"}}}}}}),
45 71 test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler)
46 72 {
47 73 using namespace ::testing;
48   - hue_bridge_state["lights"] = nlohmann::json::object();
49   - hue_bridge_state["lights"]["1"] = nlohmann::json::object();
50   - hue_bridge_state["lights"]["1"]["state"] = nlohmann::json::object();
51   - hue_bridge_state["lights"]["1"]["state"]["on"] = true;
52   - hue_bridge_state["lights"]["1"]["state"]["bri"] = 254;
53   - hue_bridge_state["lights"]["1"]["state"]["ct"] = 366;
54   - hue_bridge_state["lights"]["1"]["state"]["alert"] = "none";
55   - hue_bridge_state["lights"]["1"]["state"]["colormode"] = "ct";
56   - hue_bridge_state["lights"]["1"]["state"]["reachable"] = true;
57   - hue_bridge_state["lights"]["1"]["state"]["effect"] = "none";
58   - hue_bridge_state["lights"]["1"]["swupdate"] = nlohmann::json::object();
59   - hue_bridge_state["lights"]["1"]["swupdate"]["state"] = "noupdates";
60   - hue_bridge_state["lights"]["1"]["swupdate"]["lastinstall"] = nullptr;
61   - hue_bridge_state["lights"]["1"]["type"] = "Dimmable light";
62   - hue_bridge_state["lights"]["1"]["name"] = "Hue lamp 1";
63   - hue_bridge_state["lights"]["1"]["modelid"] = "LWB004";
64   - hue_bridge_state["lights"]["1"]["manufacturername"] = "Philips";
65   - hue_bridge_state["lights"]["1"]["productname"] = "Hue bloom";
66   - hue_bridge_state["lights"]["1"]["uniqueid"] = "00:00:00:00:00:00:00:00-00";
67   - hue_bridge_state["lights"]["1"]["swversion"] = "5.50.1.19085";
68   - hue_bridge_state["lights"]["1"]["luminaireuniqueid"] = "0000000";
69   - hue_bridge_state["lights"]["2"] = nlohmann::json::object();
70   - hue_bridge_state["lights"]["2"]["state"] = nlohmann::json::object();
71   - hue_bridge_state["lights"]["2"]["state"]["on"] = false;
72   - hue_bridge_state["lights"]["2"]["state"]["bri"] = 0;
73   - hue_bridge_state["lights"]["2"]["state"]["ct"] = 366;
74   - hue_bridge_state["lights"]["2"]["state"]["hue"] = 123456;
75   - hue_bridge_state["lights"]["2"]["state"]["sat"] = 123;
76   - hue_bridge_state["lights"]["2"]["state"]["xy"][0] = 0.102;
77   - hue_bridge_state["lights"]["2"]["state"]["xy"][1] = 0.102;
78   - hue_bridge_state["lights"]["2"]["state"]["alert"] = "none";
79   - hue_bridge_state["lights"]["2"]["state"]["colormode"] = "ct";
80   - hue_bridge_state["lights"]["2"]["state"]["reachable"] = true;
81   - hue_bridge_state["lights"]["2"]["state"]["effect"] = "none";
82   - hue_bridge_state["lights"]["2"]["swupdate"] = nlohmann::json::object();
83   - hue_bridge_state["lights"]["2"]["swupdate"]["state"] = "noupdates";
84   - hue_bridge_state["lights"]["2"]["swupdate"]["lastinstall"] = nullptr;
85   - hue_bridge_state["lights"]["2"]["type"] = "Color light";
86   - hue_bridge_state["lights"]["2"]["name"] = "Hue lamp 2";
87   - hue_bridge_state["lights"]["2"]["modelid"] = "LST001";
88   - hue_bridge_state["lights"]["2"]["uniqueid"] = "11:11:11:11:11:11:11:11-11";
89   - hue_bridge_state["lights"]["2"]["swversion"] = "5.50.1.19085";
90   - hue_bridge_state["lights"]["3"] = nlohmann::json::object();
91   - hue_bridge_state["lights"]["3"]["state"] = nlohmann::json::object();
92   - hue_bridge_state["lights"]["3"]["state"]["on"] = false;
93   - hue_bridge_state["lights"]["3"]["state"]["bri"] = 254;
94   - hue_bridge_state["lights"]["3"]["state"]["ct"] = 366;
95   - hue_bridge_state["lights"]["3"]["state"]["hue"] = 123456;
96   - hue_bridge_state["lights"]["3"]["state"]["sat"] = 123;
97   - hue_bridge_state["lights"]["3"]["state"]["xy"][0] = 0.102;
98   - hue_bridge_state["lights"]["3"]["state"]["xy"][1] = 0.102;
99   - hue_bridge_state["lights"]["3"]["state"]["alert"] = "none";
100   - hue_bridge_state["lights"]["3"]["state"]["colormode"] = "ct";
101   - hue_bridge_state["lights"]["3"]["state"]["reachable"] = true;
102   - hue_bridge_state["lights"]["3"]["state"]["effect"] = "none";
103   - hue_bridge_state["lights"]["3"]["swupdate"] = nlohmann::json::object();
104   - hue_bridge_state["lights"]["3"]["swupdate"]["state"] = "noupdates";
105   - hue_bridge_state["lights"]["3"]["swupdate"]["lastinstall"] = nullptr;
106   - hue_bridge_state["lights"]["3"]["type"] = "Extended color light";
107   - hue_bridge_state["lights"]["3"]["name"] = "Hue lamp 3";
108   - hue_bridge_state["lights"]["3"]["modelid"] = "LCT010";
109   - hue_bridge_state["lights"]["3"]["manufacturername"] = "Philips";
110   - hue_bridge_state["lights"]["3"]["productname"] = "Hue bloom";
111   - hue_bridge_state["lights"]["3"]["swversion"] = "5.50.1.19085";
112 74  
113 75 EXPECT_CALL(*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), 80))
114 76 .Times(AtLeast(1))
... ... @@ -126,7 +88,7 @@ protected:
126 88 .Times(AtLeast(1))
127 89 .WillRepeatedly(Return(hue_bridge_state["lights"]["3"]));
128 90 }
129   - ~HueLightTest(){};
  91 + ~HueLightTest() {};
130 92 };
131 93  
132 94 TEST_F(HueLightTest, Constructor)
... ... @@ -692,15 +654,15 @@ TEST_F(HueLightTest, getColorHueSaturation)
692 654 HueLight test_light_3 = test_bridge.getLight(3);
693 655  
694 656 EXPECT_EQ(std::make_pair(static_cast<uint16_t>(0), static_cast<uint8_t>(0)), ctest_light_1.getColorHueSaturation());
695   - EXPECT_EQ(std::make_pair(static_cast<uint16_t>(123456), static_cast<uint8_t>(123)),
696   - ctest_light_2.getColorHueSaturation());
697   - EXPECT_EQ(std::make_pair(static_cast<uint16_t>(123456), static_cast<uint8_t>(123)),
698   - ctest_light_3.getColorHueSaturation());
  657 + EXPECT_EQ(
  658 + std::make_pair(static_cast<uint16_t>(12345), static_cast<uint8_t>(123)), ctest_light_2.getColorHueSaturation());
  659 + EXPECT_EQ(
  660 + std::make_pair(static_cast<uint16_t>(12345), static_cast<uint8_t>(123)), ctest_light_3.getColorHueSaturation());
699 661 EXPECT_EQ(std::make_pair(static_cast<uint16_t>(0), static_cast<uint8_t>(0)), test_light_1.getColorHueSaturation());
700 662 EXPECT_EQ(
701   - std::make_pair(static_cast<uint16_t>(123456), static_cast<uint8_t>(123)), test_light_2.getColorHueSaturation());
  663 + std::make_pair(static_cast<uint16_t>(12345), static_cast<uint8_t>(123)), test_light_2.getColorHueSaturation());
702 664 EXPECT_EQ(
703   - std::make_pair(static_cast<uint16_t>(123456), static_cast<uint8_t>(123)), test_light_3.getColorHueSaturation());
  665 + std::make_pair(static_cast<uint16_t>(12345), static_cast<uint8_t>(123)), test_light_3.getColorHueSaturation());
704 666 }
705 667  
706 668 TEST_F(HueLightTest, setColorXY)
... ...
test/test_Main.cpp
... ... @@ -21,9 +21,35 @@
21 21 **/
22 22  
23 23 #include <gtest/gtest.h>
  24 +#include <hueplusplus/HueConfig.h>
  25 +
  26 +namespace
  27 +{
  28 +class TestConfig : public hueplusplus::Config
  29 +{
  30 +public:
  31 + TestConfig()
  32 + {
  33 + preAlertDelay = postAlertDelay = upnpTimeout = bridgeRequestDelay = requestUsernameDelay
  34 + = requestUsernameAttemptInterval = std::chrono::seconds(0);
  35 + }
  36 +};
  37 +
  38 +// Environment sets config to disable all delays and speed up tests
  39 +class Environment : public ::testing::Environment
  40 +{
  41 +public:
  42 + ~Environment() override {}
  43 +
  44 + void SetUp() override { hueplusplus::Config::instance() = TestConfig(); }
  45 +
  46 + void TearDown() override {}
  47 +};
  48 +} // namespace
24 49  
25 50 int main(int argc, char** argv)
26 51 {
27 52 ::testing::InitGoogleTest(&argc, argv);
  53 + ::testing::AddGlobalTestEnvironment(new Environment());
28 54 return RUN_ALL_TESTS();
29 55 }
... ...
test/test_UPnP.cpp
... ... @@ -26,6 +26,7 @@
26 26 #include "iostream"
27 27 #include "testhelper.h"
28 28  
  29 +#include "hueplusplus/HueConfig.h"
29 30 #include "hueplusplus/UPnP.h"
30 31 #include "json/json.hpp"
31 32 #include "mocks/mock_HttpHandler.h"
... ... @@ -42,7 +43,7 @@ TEST(UPnP, getDevices)
42 43 EXPECT_CALL(*handler,
43 44 sendMulticast("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: "
44 45 "\"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n",
45   - "239.255.255.250", 1900, 5))
  46 + "239.255.255.250", 1900, Config::instance().getUPnPTimeout()))
46 47 .Times(1)
47 48 .WillRepeatedly(::testing::Return(getMulticastReply()));
48 49  
... ...