Commit d3e59bb1835dbad6bb1a0a3e36343d313d2a5b7e

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent 67145ea0

Generalize StateTransaction to also work for HueLight state.

include/hueplusplus/Group.h
... ... @@ -28,44 +28,12 @@
28 28  
29 29 #include "APICache.h"
30 30 #include "HueCommandAPI.h"
  31 +#include "StateTransaction.h"
31 32  
32 33 #include "json/json.hpp"
33 34  
34 35 namespace hueplusplus
35 36 {
36   -class StateTransaction
37   -{
38   -public:
39   - StateTransaction(const HueCommandAPI& commands, const std::string& path, const nlohmann::json& currentState);
40   -
41   - StateTransaction(const StateTransaction&) = delete;
42   - StateTransaction(StateTransaction&&) = default;
43   -
44   - bool commit() &&;
45   -
46   - StateTransaction&& setOn(bool on) &&;
47   - StateTransaction&& setBrightness(uint8_t brightness) &&;
48   - StateTransaction&& setColorHue(uint16_t hue) &&;
49   - StateTransaction&& setColorSaturation(uint8_t saturation) &&;
50   - StateTransaction&& setColorHueSaturation(uint16_t hue, uint8_t saturation) &&;
51   - StateTransaction&& setColorXY(float x, float y) &&;
52   - StateTransaction&& setColorTemperature(unsigned int mired) &&;
53   - StateTransaction&& setColorLoop(bool on) &&;
54   - StateTransaction&& incrementBrightness(int increment) &&;
55   - StateTransaction&& incrementSaturation(int increment) &&;
56   - StateTransaction&& incrementHue(int increment) &&;
57   - StateTransaction&& incrementColorTemperature(int increment) &&;
58   - StateTransaction&& incrementColorXY(float xInc, float yInc) &&;
59   - StateTransaction&& setScene(const std::string& scene) &&;
60   - StateTransaction&& setTransition(uint16_t transition) &&;
61   -
62   -private:
63   - const HueCommandAPI& commands;
64   - std::string path;
65   - nlohmann::json state;
66   - nlohmann::json request;
67   -};
68   -
69 37 class Group
70 38 {
71 39 public:
... ...
include/hueplusplus/HueLight.h
... ... @@ -30,6 +30,7 @@
30 30 #include "ColorHueStrategy.h"
31 31 #include "ColorTemperatureStrategy.h"
32 32 #include "HueCommandAPI.h"
  33 +#include "StateTransaction.h"
33 34  
34 35 #include "json/json.hpp"
35 36  
... ... @@ -78,7 +79,7 @@ LLC020 // Hue Go, Color Gamut C, ECL
78 79 };*/
79 80  
80 81 //! enum that specifies the color type of all HueLights
81   -enum ColorType
  82 +enum class ColorType
82 83 {
83 84 UNDEFINED, //!< ColorType for this light is unknown or undefined
84 85 NONE, //!< light has no specific ColorType
... ... @@ -676,6 +677,8 @@ public:
676 677 return false;
677 678 };
678 679  
  680 + virtual StateTransaction transaction();
  681 +
679 682 protected:
680 683 //! \brief Protected ctor that is used by \ref Hue class.
681 684 //!
... ...
include/hueplusplus/StateTransaction.h 0 → 100644
  1 +/**
  2 + \file StateTransaction.h
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 + Copyright (C) 2020 Moritz Wirger - developer\n
  6 +
  7 + This file is part of hueplusplus.
  8 +
  9 + hueplusplus is free software: you can redistribute it and/or modify
  10 + it under the terms of the GNU Lesser General Public License as published by
  11 + the Free Software Foundation, either version 3 of the License, or
  12 + (at your option) any later version.
  13 +
  14 + hueplusplus is distributed in the hope that it will be useful,
  15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + GNU Lesser General Public License for more details.
  18 +
  19 + You should have received a copy of the GNU Lesser General Public License
  20 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  21 +**/
  22 +
  23 +#ifndef INCLUDE_HUEPLUSPLUS_STATE_TRANSACTION_H
  24 +#define INCLUDE_HUEPLUSPLUS_STATE_TRANSACTION_H
  25 +
  26 +#include <string>
  27 +
  28 +#include "HueCommandAPI.h"
  29 +
  30 +#include "json/json.hpp"
  31 +
  32 +namespace hueplusplus
  33 +{
  34 +class StateTransaction
  35 +{
  36 +public:
  37 + StateTransaction(const HueCommandAPI& commands, const std::string& path, const nlohmann::json& currentState);
  38 +
  39 + StateTransaction(const StateTransaction&) = delete;
  40 + StateTransaction(StateTransaction&&) = default;
  41 +
  42 + bool commit() &&;
  43 +
  44 + StateTransaction&& setOn(bool on) &&;
  45 + StateTransaction&& setBrightness(uint8_t brightness) &&;
  46 + StateTransaction&& setColorHue(uint16_t hue) &&;
  47 + StateTransaction&& setColorSaturation(uint8_t saturation) &&;
  48 + StateTransaction&& setColorHueSaturation(uint16_t hue, uint8_t saturation) &&;
  49 + StateTransaction&& setColorXY(float x, float y) &&;
  50 + StateTransaction&& setColorTemperature(unsigned int mired) &&;
  51 + StateTransaction&& setColorLoop(bool on) &&;
  52 + StateTransaction&& incrementBrightness(int increment) &&;
  53 + StateTransaction&& incrementSaturation(int increment) &&;
  54 + StateTransaction&& incrementHue(int increment) &&;
  55 + StateTransaction&& incrementColorTemperature(int increment) &&;
  56 + StateTransaction&& incrementColorXY(float xInc, float yInc) &&;
  57 + StateTransaction&& setTransition(uint16_t transition) &&;
  58 + StateTransaction&& alert() &&;
  59 + StateTransaction&& longAlert() &&;
  60 + StateTransaction&& stopAlert() &&;
  61 +
  62 +protected:
  63 + const HueCommandAPI& commands;
  64 + std::string path;
  65 + nlohmann::json state;
  66 + nlohmann::json request;
  67 +};
  68 +
  69 +} // namespace hueplusplus
  70 +
  71 +#endif
0 72 \ No newline at end of file
... ...
include/hueplusplus/Utils.h
... ... @@ -66,12 +66,22 @@ nlohmann::json safeGetMemberHelper(const nlohmann::json&amp; json, std::size_t index
66 66  
67 67 //! \brief Function for validating that a request was executed correctly
68 68 //!
  69 +//! \param path The path the PUT request was made to
69 70 //! \param request The request that was sent initially
70 71 //! \param reply The reply that was received
71   -//! \param lightId The identifier of the light
72 72 //! \return True if request was executed correctly
  73 +bool validatePUTReply(const std::string& path, const nlohmann::json& request, const nlohmann::json& reply);
  74 +
73 75 bool validateReplyForLight(const nlohmann::json& request, const nlohmann::json& reply, int lightId);
74 76  
  77 +//! \brief Checks equality to 4 decimal places
  78 +//!
  79 +//! Floats in Hue json responses are rounded to 4 decimal places.
  80 +inline bool floatEquals(float lhs, float rhs)
  81 +{
  82 + return std::abs(lhs - rhs) <= 1E-4f;
  83 +}
  84 +
75 85 //! \brief Returns the object/array member or null if it does not exist
76 86 //!
77 87 //! \param json The base json value
... ...
src/CMakeLists.txt
... ... @@ -14,7 +14,7 @@ set(hueplusplus_SOURCES
14 14 SimpleColorTemperatureStrategy.cpp
15 15 UPnP.cpp
16 16 Utils.cpp
17   -)
  17 + StateTransaction.cpp)
18 18  
19 19 # on windows we want to compile the WinHttpHandler
20 20 if(WIN32)
... ...
src/ExtendedColorHueStrategy.cpp
... ... @@ -200,8 +200,8 @@ bool ExtendedColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLigh
200 200 {
201 201 // Careful, only use state until any light function might refresh the value and invalidate the reference
202 202 const nlohmann::json& state = light.state.GetValue()["state"];
203   - std::string cType = state["colormode"];
204   - bool on = state["on"];
  203 + std::string cType = state["colormode"].get<std::string>();
  204 + bool on = state["on"].get<bool>();
205 205 if (cType == "hs")
206 206 {
207 207 uint16_t oldHue = state["hue"].get<uint16_t>();
... ...
src/Group.cpp
... ... @@ -2,159 +2,35 @@
2 2  
3 3 #include "hueplusplus/HueExceptionMacro.h"
4 4  
5   -hueplusplus::StateTransaction::StateTransaction(
6   - const HueCommandAPI& commands, const std::string& path, const nlohmann::json& currentState)
7   - : commands(commands), path(path), state(state), request(nlohmann::json::object())
8   -{}
9   -
10   -bool hueplusplus::StateTransaction::commit() &&
11   -{
12   - // Empty request or request with only transition makes no sense
13   - if (!request.empty() || (request.size() == 1 && request.count("transition")))
14   - {
15   - if (!request.count("on"))
16   - {
17   - if (request.value("bri", 254) == 0)
18   - {
19   - // Turn off if brightness is 0
20   - request["on"] = false;
21   - }
22   - else if (request.value("bri", 0) != 0 || request.count("colorloop") || request.count("hue")
23   - || request.count("sat") || request.count("xy"))
24   - {
25   - // Turn on if it was turned off
26   - request["on"] = true;
27   - }
28   - }
29   -
30   - commands.PUTRequest(path, request, CURRENT_FILE_INFO);
31   - return true;
32   - }
33   - return false;
34   -}
35   -
36   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::setOn(bool on) &&
37   -{
38   - request["on"] = on;
39   - return std::move(*this);
40   -}
41   -
42   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::setBrightness(uint8_t brightness) &&
43   -{
44   - request["bri"] = std::min<uint8_t>(brightness, 254);
45   - return std::move(*this);
46   -}
47   -
48   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::setColorSaturation(uint8_t saturation) &&
49   -{
50   - request["sat"] = std::min<uint8_t>(saturation, 254);
51   - return std::move(*this);
52   -}
53   -
54   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::setColorHue(uint16_t hue) &&
55   -{
56   - request["hue"] = hue;
57   - return std::move(*this);
58   -}
59   -
60   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::setColorHueSaturation(
61   - uint16_t hue, uint8_t saturation) &&
62   -{
63   - request["hue"] = hue;
64   - request["sat"] = std::min<uint8_t>(saturation, 254);
65   - return std::move(*this);
66   -}
67   -
68   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::setColorXY(float x, float y) &&
69   -{
70   - request["xy"] = {x, y};
71   - return std::move(*this);
72   -}
73   -
74   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::setColorTemperature(unsigned int mired) &&
75   -{
76   - request["ct"] = mired;
77   - return std::move(*this);
78   -}
79   -
80   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::setColorLoop(bool on) &&
  5 +namespace hueplusplus
81 6 {
82   - request["effect"] = on ? "colorloop" : "none";
83   - return std::move(*this);
84   -}
85   -
86   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::incrementBrightness(int increment) &&
87   -{
88   - request["bri_inc"] = std::max(-254, std::min(increment, 254));
89   - return std::move(*this);
90   -}
91   -
92   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::incrementSaturation(int increment) &&
93   -{
94   - request["sat_inc"] = std::max(-254, std::min(increment, 254));
95   - return std::move(*this);
96   -}
97   -
98   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::incrementHue(int increment) &&
99   -{
100   - request["hue_inc"] = std::max(-65534, std::min(increment, 65534));
101   - return std::move(*this);
102   -}
103   -
104   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::incrementColorTemperature(int increment) &&
105   -{
106   - request["ct_inc"] = std::max(-65534, std::min(increment, 65534));
107   - return std::move(*this);
108   -}
109   -
110   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::incrementColorXY(float xInc, float yInc) &&
111   -{
112   - request["xy_inc"] = {std::min(-0.5f, std::max(xInc, 0.5f)), std::min(-0.5f, std::max(yInc, 0.5f))};
113   - return std::move(*this);
114   -}
115   -
116   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::setScene(const std::string& scene) &&
117   -{
118   - request["scene"] = scene;
119   - return std::move(*this);
120   -}
121   -
122   -hueplusplus::StateTransaction&& hueplusplus::StateTransaction::setTransition(uint16_t transition) &&
123   -{
124   - if (transition != 4)
125   - {
126   - request["transitiontime"] = transition;
127   - }
128   - return std::move(*this);
129   -}
130   -
131   -hueplusplus::Group::Group(int id, const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration)
  7 +Group::Group(int id, const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration)
132 8 : id(id), state("/groups/" + std::to_string(id), commands, refreshDuration), commands(commands)
133 9 {
134 10 state.Refresh();
135 11 }
136 12  
137   -void hueplusplus::Group::Refresh()
  13 +void Group::Refresh()
138 14 {
139 15 state.Refresh();
140 16 }
141 17  
142   -int hueplusplus::Group::getId() const
  18 +int Group::getId() const
143 19 {
144 20 return id;
145 21 }
146 22  
147   -std::string hueplusplus::Group::getName() const
  23 +std::string Group::getName() const
148 24 {
149 25 return state.GetValue().at("name").get<std::string>();
150 26 }
151 27  
152   -std::string hueplusplus::Group::getType() const
  28 +std::string Group::getType() const
153 29 {
154 30 return state.GetValue().at("type").get<std::string>();
155 31 }
156 32  
157   -std::vector<int> hueplusplus::Group::getLightIds() const
  33 +std::vector<int> Group::getLightIds() const
158 34 {
159 35 const nlohmann::json& lights = state.GetValue().at("lights");
160 36 std::vector<int> ids;
... ... @@ -166,13 +42,13 @@ std::vector&lt;int&gt; hueplusplus::Group::getLightIds() const
166 42 return ids;
167 43 }
168 44  
169   -void hueplusplus::Group::setName(const std::string& name)
  45 +void Group::setName(const std::string& name)
170 46 {
171 47 nlohmann::json request = {{"name", name}};
172 48 SendPutRequest(request, "", CURRENT_FILE_INFO);
173 49 }
174 50  
175   -void hueplusplus::Group::setLights(const std::vector<int>& ids)
  51 +void Group::setLights(const std::vector<int>& ids)
176 52 {
177 53 nlohmann::json lights = nlohmann::json::array();
178 54 for (int id : ids)
... ... @@ -182,90 +58,91 @@ void hueplusplus::Group::setLights(const std::vector&lt;int&gt;&amp; ids)
182 58 SendPutRequest({{"lights", lights}}, "", CURRENT_FILE_INFO);
183 59 }
184 60  
185   -bool hueplusplus::Group::getAllOn()
  61 +bool Group::getAllOn()
186 62 {
187 63 return state.GetValue().at("state").at("all_on").get<bool>();
188 64 }
189   -bool hueplusplus::Group::getAllOn() const
  65 +bool Group::getAllOn() const
190 66 {
191 67 return state.GetValue().at("state").at("all_on").get<bool>();
192 68 }
193 69  
194   -bool hueplusplus::Group::getAnyOn()
  70 +bool Group::getAnyOn()
195 71 {
196 72 return state.GetValue().at("state").at("any_on").get<bool>();
197 73 }
198   -bool hueplusplus::Group::getAnyOn() const
  74 +bool Group::getAnyOn() const
199 75 {
200 76 return state.GetValue().at("state").at("any_on").get<bool>();
201 77 }
202 78  
203   -bool hueplusplus::Group::getActionOn()
  79 +bool Group::getActionOn()
204 80 {
205 81 return state.GetValue().at("action").at("on").get<bool>();
206 82 }
207   -bool hueplusplus::Group::getActionOn() const
  83 +bool Group::getActionOn() const
208 84 {
209 85 return state.GetValue().at("action").at("on").get<bool>();
210 86 }
211 87  
212   -std::pair<uint16_t, uint8_t> hueplusplus::Group::getActionHueSaturation()
  88 +std::pair<uint16_t, uint8_t> Group::getActionHueSaturation()
213 89 {
214 90 const nlohmann::json& action = state.GetValue().at("action");
215 91  
216 92 return std::make_pair(action.at("hue").get<int>(), action.at("sat").get<int>());
217 93 }
218   -std::pair<uint16_t, uint8_t> hueplusplus::Group::getActionHueSaturation() const
  94 +std::pair<uint16_t, uint8_t> Group::getActionHueSaturation() const
219 95 {
220 96 const nlohmann::json& action = state.GetValue().at("action");
221 97  
222 98 return std::make_pair(action.at("hue").get<int>(), action.at("sat").get<int>());
223 99 }
224 100  
225   -unsigned int hueplusplus::Group::getActionBrightness()
  101 +unsigned int Group::getActionBrightness()
226 102 {
227 103 return state.GetValue().at("action").at("bri").get<int>();
228 104 }
229   -unsigned int hueplusplus::Group::getActionBrightness() const
  105 +unsigned int Group::getActionBrightness() const
230 106 {
231 107 return state.GetValue().at("action").at("bri").get<int>();
232 108 }
233 109  
234   -unsigned int hueplusplus::Group::getActionColorTemperature()
  110 +unsigned int Group::getActionColorTemperature()
235 111 {
236 112 return state.GetValue().at("action").at("ct").get<int>();
237 113 }
238   -unsigned int hueplusplus::Group::getActionColorTemperature() const
  114 +unsigned int Group::getActionColorTemperature() const
239 115 {
240 116 return state.GetValue().at("action").at("ct").get<int>();
241 117 }
242 118  
243   -std::pair<float, float> hueplusplus::Group::getActionColorXY()
  119 +std::pair<float, float> Group::getActionColorXY()
244 120 {
245 121 const nlohmann::json& xy = state.GetValue().at("action").at("xy");
246 122 return std::pair<float, float>(xy[0].get<float>(), xy[1].get<float>());
247 123 }
248   -std::pair<float, float> hueplusplus::Group::getActionColorXY() const
  124 +std::pair<float, float> Group::getActionColorXY() const
249 125 {
250 126 const nlohmann::json& xy = state.GetValue().at("action").at("xy");
251 127 return std::pair<float, float>(xy[0].get<float>(), xy[1].get<float>());
252 128 }
253 129  
254   -std::string hueplusplus::Group::getActionColorMode()
  130 +std::string Group::getActionColorMode()
255 131 {
256 132 return state.GetValue().at("action").at("colormode").get<std::string>();
257 133 }
258   -std::string hueplusplus::Group::getActionColorMode() const
  134 +std::string Group::getActionColorMode() const
259 135 {
260 136 return state.GetValue().at("action").at("colormode").get<std::string>();
261 137 }
262 138  
263   -hueplusplus::StateTransaction hueplusplus::Group::transaction()
  139 +StateTransaction Group::transaction()
264 140 {
265   - return StateTransaction(commands, "/groups/" + std::to_string(id) + "/action", state.GetValue());
  141 + // Do not pass state, because it is not the state of ALL lights in the group
  142 + return StateTransaction(commands, "/groups/" + std::to_string(id) + "/action", nlohmann::json::object());
266 143 }
267 144  
268   -void hueplusplus::Group::setOn(bool on, uint8_t transition)
  145 +void Group::setOn(bool on, uint8_t transition)
269 146 {
270 147 nlohmann::json request = {{"on", on}};
271 148 if (transition != 4)
... ... @@ -275,83 +152,83 @@ void hueplusplus::Group::setOn(bool on, uint8_t transition)
275 152 SendPutRequest(request, "/action", CURRENT_FILE_INFO);
276 153 }
277 154  
278   -void hueplusplus::Group::setBrightness(uint8_t brightness, uint8_t transition)
  155 +void Group::setBrightness(uint8_t brightness, uint8_t transition)
279 156 {
280 157 transaction().setBrightness(brightness).setTransition(transition).commit();
281 158 }
282 159  
283   -void hueplusplus::Group::setColorHueSaturation(uint16_t hue, uint8_t saturation, uint8_t transition)
  160 +void Group::setColorHueSaturation(uint16_t hue, uint8_t saturation, uint8_t transition)
284 161 {
285 162 transaction().setColorHueSaturation(hue, saturation).setTransition(transition).commit();
286 163 }
287 164  
288   -void hueplusplus::Group::setColorXY(float x, float y, uint8_t transition)
  165 +void Group::setColorXY(float x, float y, uint8_t transition)
289 166 {
290 167 transaction().setColorXY(x, y).setTransition(transition).commit();
291 168 }
292 169  
293   -void hueplusplus::Group::setColorTemperature(unsigned int mired, uint8_t transition)
  170 +void Group::setColorTemperature(unsigned int mired, uint8_t transition)
294 171 {
295 172 transaction().setColorTemperature(mired).setTransition(transition).commit();
296 173 }
297 174  
298   -void hueplusplus::Group::setColorLoop(bool on, uint8_t transition)
  175 +void Group::setColorLoop(bool on, uint8_t transition)
299 176 {
300 177 transaction().setColorLoop(on).setTransition(transition);
301 178 }
302 179  
303   -void hueplusplus::Group::incrementBrightness(int increment, uint8_t transition)
  180 +void Group::incrementBrightness(int increment, uint8_t transition)
304 181 {
305 182 transaction().incrementBrightness(increment).setTransition(transition).commit();
306 183 }
307 184  
308   -void hueplusplus::Group::incrementSaturation(int increment, uint8_t transition)
  185 +void Group::incrementSaturation(int increment, uint8_t transition)
309 186 {
310 187 transaction().incrementSaturation(increment).setTransition(transition).commit();
311 188 }
312 189  
313   -void hueplusplus::Group::incrementHue(int increment, uint8_t transition)
  190 +void Group::incrementHue(int increment, uint8_t transition)
314 191 {
315 192 transaction().incrementHue(increment).setTransition(transition).commit();
316 193 }
317 194  
318   -void hueplusplus::Group::incrementColorTemperature(int increment, uint8_t transition)
  195 +void Group::incrementColorTemperature(int increment, uint8_t transition)
319 196 {
320 197 transaction().incrementColorTemperature(increment).setTransition(transition).commit();
321 198 }
322 199  
323   -void hueplusplus::Group::incrementColorXY(float incX, float incY, uint8_t transition)
  200 +void Group::incrementColorXY(float incX, float incY, uint8_t transition)
324 201 {
325 202 transaction().incrementColorXY(incX, incY).setTransition(transition).commit();
326 203 }
327 204  
328   -void hueplusplus::Group::setScene(const std::string& scene, uint8_t transition)
  205 +void Group::setScene(const std::string& scene, uint8_t transition)
329 206 {
330   - transaction().setScene(scene).setTransition(transition).commit();
  207 + SendPutRequest({ {"scene", scene} }, "/action", CURRENT_FILE_INFO);
331 208 }
332 209  
333   -nlohmann::json hueplusplus::Group::SendPutRequest(
334   - const nlohmann::json& request, const std::string& subPath, FileInfo fileInfo)
  210 +nlohmann::json Group::SendPutRequest(const nlohmann::json& request, const std::string& subPath, FileInfo fileInfo)
335 211 {
336 212 return commands.PUTRequest("/groups/" + std::to_string(id) + subPath, request, std::move(fileInfo));
337 213 }
338 214  
339   -std::string hueplusplus::Group::getRoomType() const
  215 +std::string Group::getRoomType() const
340 216 {
341 217 return state.GetValue().at("class").get<std::string>();
342 218 }
343 219  
344   -void hueplusplus::Group::setRoomType(const std::string& type)
  220 +void Group::setRoomType(const std::string& type)
345 221 {
346 222 SendPutRequest({{"class", type}}, "", CURRENT_FILE_INFO);
347 223 }
348 224  
349   -std::string hueplusplus::Group::getModelId() const
  225 +std::string Group::getModelId() const
350 226 {
351 227 return state.GetValue().at("modelid").get<std::string>();
352 228 }
353 229  
354   -std::string hueplusplus::Group::getUniqueId() const
  230 +std::string Group::getUniqueId() const
355 231 {
356 232 return state.GetValue().at("uniqueid").get<std::string>();
357 233 }
  234 +} // namespace hueplusplus
... ...
src/HueLight.cpp
... ... @@ -34,60 +34,22 @@ namespace hueplusplus
34 34 {
35 35 bool HueLight::On(uint8_t transition)
36 36 {
37   - nlohmann::json request = nlohmann::json::object();
38   - if (transition != 4)
39   - {
40   - request["transitiontime"] = transition;
41   - }
42   - if (state.GetValue()["state"]["on"] != true)
43   - {
44   - request["on"] = true;
45   - }
46   -
47   - if (!request.count("on"))
48   - {
49   - // Nothing needs to be changed
50   - return true;
51   - }
52   -
53   - nlohmann::json reply = SendPutRequest(request, "/state", CURRENT_FILE_INFO);
54   -
55   - // Check whether request was successful
56   - return utils::validateReplyForLight(request, reply, id);
  37 + return transaction().setOn(true).setTransition(transition).commit();
57 38 }
58 39  
59 40 bool HueLight::Off(uint8_t transition)
60 41 {
61   - nlohmann::json request = nlohmann::json::object();
62   - if (transition != 4)
63   - {
64   - request["transitiontime"] = transition;
65   - }
66   - if (state.GetValue()["state"]["on"] != false)
67   - {
68   - request["on"] = false;
69   - }
70   -
71   - if (!request.count("on"))
72   - {
73   - // Nothing needs to be changed
74   - return true;
75   - }
76   -
77   - nlohmann::json reply = SendPutRequest(request, "/state", CURRENT_FILE_INFO);
78   -
79   - // Check whether request was successful
80   - return utils::validateReplyForLight(request, reply, id);
  42 + return transaction().setOn(false).setTransition(transition).commit();
81 43 }
82 44  
83 45 bool HueLight::isOn()
84 46 {
85   - return state.GetValue()["state"]["on"].get<bool>();
  47 + return state.GetValue().at("state").at("on").get<bool>();
86 48 }
87 49  
88 50 bool HueLight::isOn() const
89 51 {
90   - return state.GetValue()["state"]["on"].get<bool>();
  52 + return state.GetValue().at("state").at("on").get<bool>();
91 53 }
92 54  
93 55 int HueLight::getId() const
... ... @@ -173,12 +135,12 @@ unsigned int HueLight::MiredToKelvin(unsigned int mired) const
173 135  
174 136 bool HueLight::alert()
175 137 {
176   - nlohmann::json request;
177   - request["alert"] = "select";
178   -
179   - nlohmann::json reply = SendPutRequest(request, "/state", CURRENT_FILE_INFO);
  138 + return transaction().alert().commit();
  139 +}
180 140  
181   - return utils::validateReplyForLight(request, reply, id);
  141 +StateTransaction HueLight::transaction()
  142 +{
  143 + return StateTransaction(commands, "/lights/" + std::to_string(id) + "/state", state.GetValue().at("state"));
182 144 }
183 145  
184 146 HueLight::HueLight(int id, const HueCommandAPI& commands) : HueLight(id, commands, nullptr, nullptr, nullptr) {}
... ... @@ -187,12 +149,12 @@ HueLight::HueLight(int id, const HueCommandAPI&amp; commands, std::shared_ptr&lt;const
187 149 std::shared_ptr<const ColorTemperatureStrategy> colorTempStrategy,
188 150 std::shared_ptr<const ColorHueStrategy> colorHueStrategy, std::chrono::steady_clock::duration refreshDuration)
189 151 : id(id),
  152 + state("/lights/" + std::to_string(id), commands, refreshDuration),
  153 + colorType(ColorType::NONE),
190 154 brightnessStrategy(std::move(brightnessStrategy)),
191 155 colorTemperatureStrategy(std::move(colorTempStrategy)),
192 156 colorHueStrategy(std::move(colorHueStrategy)),
193   - commands(commands),
194   - state("/lights/" + std::to_string(id), commands, refreshDuration)
195   -
  157 + commands(commands)
196 158 {
197 159 state.Refresh();
198 160 }
... ...
src/SimpleBrightnessStrategy.cpp
... ... @@ -34,49 +34,7 @@ namespace hueplusplus
34 34 bool SimpleBrightnessStrategy::setBrightness(unsigned int bri, uint8_t transition, HueLight& light) const
35 35 {
36 36 // Careful, only use state until any light function might refresh the value and invalidate the reference
37   - const nlohmann::json& state = light.state.GetValue()["state"];
38   - if (bri == 0)
39   - {
40   - if (state["on"] == true)
41   - {
42   - return light.Off(transition);
43   - }
44   - else
45   - {
46   - return true;
47   - }
48   - }
49   - else
50   - {
51   - nlohmann::json request = nlohmann::json::object();
52   - if (transition != 4)
53   - {
54   - request["transitiontime"] = transition;
55   - }
56   - if (state["on"] != true)
57   - {
58   - request["on"] = true;
59   - }
60   - if (state["bri"] != bri)
61   - {
62   - if (bri > 254)
63   - {
64   - bri = 254;
65   - }
66   - request["bri"] = bri;
67   - }
68   -
69   - if (!request.count("on") && !request.count("bri"))
70   - {
71   - // Nothing needs to be changed
72   - return true;
73   - }
74   -
75   - nlohmann::json reply = light.SendPutRequest(request, "/state", CURRENT_FILE_INFO);
76   -
77   - // Check whether request was successful
78   - return utils::validateReplyForLight(request, reply, light.id);
79   - }
  37 + return light.transaction().setBrightness(bri).setTransition(transition).commit();
80 38 }
81 39  
82 40 unsigned int SimpleBrightnessStrategy::getBrightness(HueLight& light) const
... ...
src/SimpleColorHueStrategy.cpp
... ... @@ -34,140 +34,22 @@ namespace hueplusplus
34 34 {
35 35 bool SimpleColorHueStrategy::setColorHue(uint16_t hue, uint8_t transition, HueLight& light) const
36 36 {
37   - // Careful, only use state until any light function might refresh the value and invalidate the reference
38   - const nlohmann::json& state = light.state.GetValue()["state"];
39   - nlohmann::json request = nlohmann::json::object();
40   - if (transition != 4)
41   - {
42   - request["transitiontime"] = transition;
43   - }
44   - if (state["on"] != true)
45   - {
46   - request["on"] = true;
47   - }
48   - if (state["hue"] != hue || state["colormode"] != "hs")
49   - {
50   - hue = hue % 65535;
51   - request["hue"] = hue;
52   - }
53   -
54   - if (!request.count("on") && !request.count("hue"))
55   - {
56   - // Nothing needs to be changed
57   - return true;
58   - }
59   -
60   - nlohmann::json reply = light.SendPutRequest(request, "/state", CURRENT_FILE_INFO);
61   -
62   - // Check whether request was successful
63   - return utils::validateReplyForLight(request, reply, light.id);
  37 + return light.transaction().setColorHue(hue).setTransition(transition).commit();
64 38 }
65 39  
66 40 bool SimpleColorHueStrategy::setColorSaturation(uint8_t sat, uint8_t transition, HueLight& light) const
67 41 {
68   - // Careful, only use state until any light function might refresh the value and invalidate the reference
69   - const nlohmann::json& state = light.state.GetValue()["state"];
70   - nlohmann::json request = nlohmann::json::object();
71   - if (transition != 4)
72   - {
73   - request["transitiontime"] = transition;
74   - }
75   - if (state["on"] != true)
76   - {
77   - request["on"] = true;
78   - }
79   - if (state["sat"] != sat)
80   - {
81   - if (sat > 254)
82   - {
83   - sat = 254;
84   - }
85   - request["sat"] = sat;
86   - }
87   -
88   - if (!request.count("on") && !request.count("sat"))
89   - {
90   - // Nothing needs to be changed
91   - return true;
92   - }
93   -
94   - nlohmann::json reply = light.SendPutRequest(request, "/state", CURRENT_FILE_INFO);
95   -
96   - // Check whether request was successful
97   - return utils::validateReplyForLight(request, reply, light.id);
  42 + return light.transaction().setColorSaturation(sat).setTransition(transition).commit();
98 43 }
99 44  
100 45 bool SimpleColorHueStrategy::setColorHueSaturation(uint16_t hue, uint8_t sat, uint8_t transition, HueLight& light) const
101 46 {
102   - // Careful, only use state until any light function might refresh the value and invalidate the reference
103   - const nlohmann::json& state = light.state.GetValue()["state"];
104   - nlohmann::json request = nlohmann::json::object();
105   -
106   - if (transition != 4)
107   - {
108   - request["transitiontime"] = transition;
109   - }
110   - if (state["on"] != true)
111   - {
112   - request["on"] = true;
113   - }
114   - if (state["hue"] != hue || state["colormode"] != "hs")
115   - {
116   - hue = hue % 65535;
117   - request["hue"] = hue;
118   - }
119   - if (state["sat"] != sat || state["colormode"] != "hs")
120   - {
121   - if (sat > 254)
122   - {
123   - sat = 254;
124   - }
125   - request["sat"] = sat;
126   - }
127   -
128   - if (!request.count("on") && !request.count("hue") && !request.count("sat"))
129   - {
130   - // Nothing needs to be changed
131   - return true;
132   - }
133   -
134   - nlohmann::json reply = light.SendPutRequest(request, "/state", CURRENT_FILE_INFO);
135   -
136   - // Check whether request was successful
137   - return utils::validateReplyForLight(request, reply, light.id);
  47 + return light.transaction().setColorHueSaturation(hue, sat).setTransition(transition).commit();
138 48 }
139 49  
140 50 bool SimpleColorHueStrategy::setColorXY(float x, float y, uint8_t transition, HueLight& light) const
141 51 {
142   - // Careful, only use state until any light function might refresh the value and invalidate the reference
143   - const nlohmann::json& state = light.state.GetValue()["state"];
144   - nlohmann::json request = nlohmann::json::object();
145   -
146   - if (transition != 4)
147   - {
148   - request["transitiontime"] = transition;
149   - }
150   - if (state["on"] != true)
151   - {
152   - request["on"] = true;
153   - }
154   - if (std::abs(state["xy"][0].get<float>() - x) > 1E-4f || std::abs(state["xy"][1].get<float>() - y) > 1E-4f
155   - || state["colormode"] != "xy")
156   - {
157   - request["xy"][0] = x;
158   - request["xy"][1] = y;
159   - }
160   -
161   - if (!request.count("on") && !request.count("xy"))
162   - {
163   - // Nothing needs to be changed
164   - return true;
165   - }
166   -
167   - nlohmann::json reply = light.SendPutRequest(request, "/state", CURRENT_FILE_INFO);
168   -
169   - // Check whether request was successful
170   - return utils::validateReplyForLight(request, reply, light.id);
  52 + return light.transaction().setColorXY(x, y).setTransition(transition).commit();
171 53 }
172 54  
173 55 bool SimpleColorHueStrategy::setColorRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t transition, HueLight& light) const
... ... @@ -198,30 +80,7 @@ bool SimpleColorHueStrategy::setColorRGB(uint8_t r, uint8_t g, uint8_t b, uint8_
198 80  
199 81 bool SimpleColorHueStrategy::setColorLoop(bool on, HueLight& light) const
200 82 {
201   - // colorloop
202   - // Careful, only use state until any light function might refresh the value and invalidate the reference
203   - const nlohmann::json& state = light.state.GetValue()["state"];
204   - nlohmann::json request = nlohmann::json::object();
205   -
206   - if (state["on"] != true)
207   - {
208   - request["on"] = true;
209   - }
210   - std::string effect;
211   - if ((effect = on ? "colorloop" : "none") != state["effect"])
212   - {
213   - request["effect"] = effect;
214   - }
215   - if (!request.count("on") && !request.count("effect"))
216   - {
217   - // Nothing needs to be changed
218   - return true;
219   - }
220   -
221   - nlohmann::json reply = light.SendPutRequest(request, "/state", CURRENT_FILE_INFO);
222   -
223   - // Check whether request was successful
224   - return utils::validateReplyForLight(request, reply, light.id);
  83 + return light.transaction().setColorLoop(true).commit();
225 84 }
226 85  
227 86 bool SimpleColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, HueLight& light) const
... ...
src/SimpleColorTemperatureStrategy.cpp
... ... @@ -34,40 +34,7 @@ namespace hueplusplus
34 34 {
35 35 bool SimpleColorTemperatureStrategy::setColorTemperature(unsigned int mired, uint8_t transition, HueLight& light) const
36 36 {
37   - // Careful, only use state until any light function might refresh the value and invalidate the reference
38   - const nlohmann::json& state = light.state.GetValue()["state"];
39   - nlohmann::json request = nlohmann::json::object();
40   - if (transition != 4)
41   - {
42   - request["transitiontime"] = transition;
43   - }
44   - if (state["on"] != true)
45   - {
46   - request["on"] = true;
47   - }
48   - if (state["ct"] != mired)
49   - {
50   - if (mired > 500)
51   - {
52   - mired = 500;
53   - }
54   - if (mired < 153)
55   - {
56   - mired = 153;
57   - }
58   - request["ct"] = mired;
59   - }
60   -
61   - if (!request.count("on") && !request.count("ct"))
62   - {
63   - // Nothing needs to be changed
64   - return true;
65   - }
66   -
67   - nlohmann::json reply = light.SendPutRequest(request, "/state", CURRENT_FILE_INFO);
68   -
69   - // Check whether request was successful
70   - return utils::validateReplyForLight(request, reply, light.id);
  37 + return light.transaction().setColorTemperature(mired).setTransition(transition).commit();
71 38 }
72 39  
73 40 bool SimpleColorTemperatureStrategy::alertTemperature(unsigned int mired, HueLight& light) const
... ...
src/StateTransaction.cpp 0 → 100644
  1 +/**
  2 + \file StateTransaction.cpp
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 + Copyright (C) 2020 Moritz Wirger - developer\n
  6 +
  7 + This file is part of hueplusplus.
  8 +
  9 + hueplusplus is free software: you can redistribute it and/or modify
  10 + it under the terms of the GNU Lesser General Public License as published by
  11 + the Free Software Foundation, either version 3 of the License, or
  12 + (at your option) any later version.
  13 +
  14 + hueplusplus is distributed in the hope that it will be useful,
  15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + GNU Lesser General Public License for more details.
  18 +
  19 + You should have received a copy of the GNU Lesser General Public License
  20 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  21 +**/
  22 +
  23 +#include "hueplusplus/StateTransaction.h"
  24 +
  25 +#include "hueplusplus/HueExceptionMacro.h"
  26 +#include "hueplusplus/StateTransaction.h"
  27 +#include "hueplusplus/Utils.h"
  28 +
  29 +namespace hueplusplus
  30 +{
  31 +StateTransaction::StateTransaction(
  32 + const HueCommandAPI& commands, const std::string& path, const nlohmann::json& currentState)
  33 + : commands(commands), path(path), state(currentState), request(nlohmann::json::object())
  34 +{}
  35 +
  36 +bool StateTransaction::commit() &&
  37 +{
  38 + // Empty request or request with only transition makes no sense
  39 + if (!request.empty() && !(request.size() == 1 && request.count("transitiontime")))
  40 + {
  41 + if (!request.count("on"))
  42 + {
  43 + if (request.value("bri", 254) == 0 && state.value("on", true))
  44 + {
  45 + // Turn off if brightness is 0
  46 + request["on"] = false;
  47 + }
  48 + else if (!state.value("on", false)
  49 + && (request.value("bri", 0) != 0 || request.count("effect") || request.count("hue")
  50 + || request.count("sat") || request.count("xy") || request.count("ct")))
  51 + {
  52 + // Turn on if it was turned off
  53 + request["on"] = true;
  54 + }
  55 + }
  56 +
  57 + nlohmann::json reply = commands.PUTRequest(path, request, CURRENT_FILE_INFO);
  58 + return utils::validatePUTReply(path, request, reply);
  59 + }
  60 + return true;
  61 +}
  62 +
  63 +StateTransaction&& StateTransaction::setOn(bool on) &&
  64 +{
  65 + if (!state.count("on") || state["on"] != on)
  66 + {
  67 + request["on"] = on;
  68 + }
  69 + return std::move(*this);
  70 +}
  71 +
  72 +StateTransaction&& StateTransaction::setBrightness(uint8_t brightness) &&
  73 +{
  74 + uint8_t clamped = std::min<uint8_t>(brightness, 254);
  75 + if (!state.count("bri") || state["bri"].get<unsigned int>() != clamped)
  76 + {
  77 + request["bri"] = clamped;
  78 + }
  79 + return std::move(*this);
  80 +}
  81 +
  82 +StateTransaction&& StateTransaction::setColorSaturation(uint8_t saturation) &&
  83 +{
  84 + uint8_t clamped = std::min<uint8_t>(saturation, 254);
  85 + if (!state.count("sat") || state["sat"].get<unsigned int>() != clamped || state.value("colormode", "") != "hs")
  86 + {
  87 + request["sat"] = clamped;
  88 + }
  89 + return std::move(*this);
  90 +}
  91 +
  92 +StateTransaction&& StateTransaction::setColorHue(uint16_t hue) &&
  93 +{
  94 + if (!state.count("hue") || state["hue"].get<int>() != hue || state.value("colormode", "") != "hs")
  95 + {
  96 + request["hue"] = hue;
  97 + }
  98 + return std::move(*this);
  99 +}
  100 +
  101 +StateTransaction&& StateTransaction::setColorHueSaturation(uint16_t hue, uint8_t saturation) &&
  102 +{
  103 + if (!state.count("hue") || state["hue"].get<int>() != hue)
  104 + {
  105 + request["hue"] = hue;
  106 + }
  107 + uint8_t clamped = std::min<uint8_t>(saturation, 254);
  108 + if (!state.count("sat") || state["sat"].get<unsigned int>() != clamped)
  109 + {
  110 + request["sat"] = clamped;
  111 + }
  112 + return std::move(*this);
  113 +}
  114 +
  115 +StateTransaction&& StateTransaction::setColorXY(float x, float y) &&
  116 +{
  117 + if (!state.count("xy") || !state.count("colormode") || !state["xy"].is_array()
  118 + || !utils::floatEquals(state["xy"][0].get<float>(), x) || !utils::floatEquals(state["xy"][1].get<float>(), y)
  119 + || state["colormode"] != "xy")
  120 + {
  121 + request["xy"] = {x, y};
  122 + }
  123 + return std::move(*this);
  124 +}
  125 +
  126 +StateTransaction&& StateTransaction::setColorTemperature(unsigned int mired) &&
  127 +{
  128 + unsigned int clamped = std::max(153u, std::min(mired, 500u));
  129 + if (state.value("ct", 0u) != clamped || state.value("colormode", "") != "ct")
  130 + {
  131 + request["ct"] = clamped;
  132 + }
  133 + return std::move(*this);
  134 +}
  135 +
  136 +StateTransaction&& StateTransaction::setColorLoop(bool on) &&
  137 +{
  138 + std::string effect = on ? "colorloop" : "none";
  139 + if (state.value("effect", "") != effect)
  140 + {
  141 + request["effect"] = effect;
  142 + }
  143 + return std::move(*this);
  144 +}
  145 +
  146 +StateTransaction&& StateTransaction::incrementBrightness(int increment) &&
  147 +{
  148 + request["bri_inc"] = std::max(-254, std::min(increment, 254));
  149 + return std::move(*this);
  150 +}
  151 +
  152 +StateTransaction&& StateTransaction::incrementSaturation(int increment) &&
  153 +{
  154 + request["sat_inc"] = std::max(-254, std::min(increment, 254));
  155 + return std::move(*this);
  156 +}
  157 +
  158 +StateTransaction&& StateTransaction::incrementHue(int increment) &&
  159 +{
  160 + request["hue_inc"] = std::max(-65534, std::min(increment, 65534));
  161 + return std::move(*this);
  162 +}
  163 +
  164 +StateTransaction&& StateTransaction::incrementColorTemperature(int increment) &&
  165 +{
  166 + request["ct_inc"] = std::max(-65534, std::min(increment, 65534));
  167 + return std::move(*this);
  168 +}
  169 +
  170 +StateTransaction&& StateTransaction::incrementColorXY(float xInc, float yInc) &&
  171 +{
  172 + request["xy_inc"] = {std::min(-0.5f, std::max(xInc, 0.5f)), std::min(-0.5f, std::max(yInc, 0.5f))};
  173 + return std::move(*this);
  174 +}
  175 +
  176 +StateTransaction&& StateTransaction::setTransition(uint16_t transition) &&
  177 +{
  178 + if (transition != 4)
  179 + {
  180 + request["transitiontime"] = transition;
  181 + }
  182 + return std::move(*this);
  183 +}
  184 +StateTransaction&& StateTransaction::alert() &&
  185 +{
  186 + request["alert"] = "select";
  187 + return std::move(*this);
  188 +}
  189 +StateTransaction&& StateTransaction::longAlert() &&
  190 +{
  191 + request["alert"] = "lselect";
  192 + return std::move(*this);
  193 +}
  194 +StateTransaction&& StateTransaction::stopAlert() &&
  195 +{
  196 + request["alert"] = "none";
  197 + return std::move(*this);
  198 +}
  199 +} // namespace hueplusplus
0 200 \ No newline at end of file
... ...
src/Utils.cpp
... ... @@ -28,10 +28,14 @@ namespace hueplusplus
28 28 {
29 29 namespace utils
30 30 {
31   -bool validateReplyForLight(const nlohmann::json& request, const nlohmann::json& reply, int lightId)
  31 +bool validatePUTReply(const std::string& path, const nlohmann::json& request, const nlohmann::json& reply)
32 32 {
  33 + std::string pathAppend = path;
  34 + if (pathAppend.back() != '/')
  35 + {
  36 + pathAppend.push_back('/');
  37 + }
33 38 bool success = false;
34   - std::string path = "/lights/" + std::to_string(lightId) + "/state/";
35 39 for (auto it = reply.begin(); it != reply.end(); ++it)
36 40 {
37 41 success = it.value().count("success");
... ... @@ -42,9 +46,9 @@ bool validateReplyForLight(const nlohmann::json&amp; request, const nlohmann::json&amp;
42 46 for (auto successIt = successObject.begin(); successIt != successObject.end(); ++successIt)
43 47 {
44 48 const std::string successPath = successIt.key();
45   - if (successPath.find(path) == 0)
  49 + if (successPath.find(pathAppend) == 0)
46 50 {
47   - const std::string valueKey = successPath.substr(path.size());
  51 + const std::string valueKey = successPath.substr(pathAppend.size());
48 52 auto requestIt = request.find(valueKey);
49 53 success = requestIt != request.end();
50 54 if (success)
... ... @@ -58,7 +62,8 @@ bool validateReplyForLight(const nlohmann::json&amp; request, const nlohmann::json&amp;
58 62 }
59 63 else
60 64 {
61   - success = requestIt.value() == successIt.value();
  65 + success = requestIt.value() == successIt.value()
  66 + || (successIt.value().is_string() && successIt.value() == "Updated.");
62 67 }
63 68 if (!success)
64 69 {
... ... @@ -80,5 +85,10 @@ bool validateReplyForLight(const nlohmann::json&amp; request, const nlohmann::json&amp;
80 85 }
81 86 return success;
82 87 }
  88 +
  89 +bool validateReplyForLight(const nlohmann::json& request, const nlohmann::json& reply, int lightId)
  90 +{
  91 + return validatePUTReply("/lights/" + std::to_string(lightId) + "/state/", request, reply);
  92 +}
83 93 } // namespace utils
84 94 } // namespace hueplusplus
... ...
test/CMakeLists.txt
... ... @@ -70,6 +70,9 @@ add_custom_target(&quot;unittest&quot;
70 70 find_program( GCOV_PATH gcov )
71 71 find_program( LCOV_PATH lcov )
72 72  
  73 +mark_as_advanced(GCOV_PATH)
  74 +mark_as_advanced(LCOV_PATH)
  75 +
73 76 if(LCOV_PATH AND GCOV_PATH)
74 77 # GCov
75 78 include(CodeCoverage.cmake)
... ...
test/test_HueLight.cpp
... ... @@ -69,7 +69,7 @@ protected:
69 69 hue_bridge_state["lights"]["2"] = nlohmann::json::object();
70 70 hue_bridge_state["lights"]["2"]["state"] = nlohmann::json::object();
71 71 hue_bridge_state["lights"]["2"]["state"]["on"] = false;
72   - hue_bridge_state["lights"]["2"]["state"]["bri"] = 254;
  72 + hue_bridge_state["lights"]["2"]["state"]["bri"] = 0;
73 73 hue_bridge_state["lights"]["2"]["state"]["ct"] = 366;
74 74 hue_bridge_state["lights"]["2"]["state"]["hue"] = 123456;
75 75 hue_bridge_state["lights"]["2"]["state"]["sat"] = 123;
... ... @@ -514,7 +514,7 @@ TEST_F(HueLightTest, setBrightness)
514 514 prep_ret[1]["success"]["/lights/3/state/on"] = true;
515 515 prep_ret[2] = nlohmann::json::object();
516 516 prep_ret[2]["success"] = nlohmann::json::object();
517   - prep_ret[2]["success"]["/lights/3/state/bri"] = 254;
  517 + prep_ret[2]["success"]["/lights/3/state/bri"] = 253;
518 518 EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
519 519 .Times(1)
520 520 .WillOnce(Return(prep_ret));
... ... @@ -525,7 +525,7 @@ TEST_F(HueLightTest, setBrightness)
525 525  
526 526 EXPECT_EQ(false, test_light_1.setBrightness(200));
527 527 EXPECT_EQ(true, test_light_2.setBrightness(0, 2));
528   - EXPECT_EQ(true, test_light_3.setBrightness(255, 0));
  528 + EXPECT_EQ(true, test_light_3.setBrightness(253, 0));
529 529 }
530 530  
531 531 TEST_F(HueLightTest, getBrightness)
... ... @@ -538,10 +538,10 @@ TEST_F(HueLightTest, getBrightness)
538 538 HueLight test_light_3 = test_bridge.getLight(3);
539 539  
540 540 EXPECT_EQ(254, ctest_light_1.getBrightness());
541   - EXPECT_EQ(254, ctest_light_2.getBrightness());
  541 + EXPECT_EQ(0, ctest_light_2.getBrightness());
542 542 EXPECT_EQ(254, ctest_light_3.getBrightness());
543 543 EXPECT_EQ(254, test_light_1.getBrightness());
544   - EXPECT_EQ(254, test_light_2.getBrightness());
  544 + EXPECT_EQ(0, test_light_2.getBrightness());
545 545 EXPECT_EQ(254, test_light_3.getBrightness());
546 546 }
547 547  
... ...
test/test_SimpleBrightnessStrategy.cpp
... ... @@ -46,33 +46,30 @@ TEST(SimpleBrightnessStrategy, setBrightness)
46 46 .WillRepeatedly(Return(nlohmann::json::object()));
47 47 MockHueLight test_light(handler);
48 48  
49   - EXPECT_CALL(test_light, Off(_)).Times(AtLeast(1)).WillRepeatedly(Return(true));
50   - nlohmann::json prep_ret;
51   - prep_ret = nlohmann::json::array();
52   - prep_ret[0] = nlohmann::json::object();
53   - prep_ret[0]["success"] = nlohmann::json::object();
54   - prep_ret[0]["success"]["/lights/1/state/transitiontime"] = 6;
55   - prep_ret[1] = nlohmann::json::object();
56   - prep_ret[1]["success"] = nlohmann::json::object();
57   - prep_ret[1]["success"]["/lights/1/state/on"] = true;
58   - prep_ret[2] = nlohmann::json::object();
59   - prep_ret[2]["success"] = nlohmann::json::object();
60   - prep_ret[2]["success"]["/lights/1/state/bri"] = 50;
61   - EXPECT_CALL(test_light, SendPutRequest(_, "/state", _)).Times(1).WillOnce(Return(prep_ret));
  49 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
62 50  
  51 + nlohmann::json prep_ret
  52 + = {{{"success", {{"/lights/1/state/on", false}}}}, {{"success", {{"/lights/1/state/bri", 0}}}}};
  53 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
63 54 test_light.getState()["state"]["on"] = true;
64 55 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(0, 4, test_light));
  56 + // Only set brightness, already off
65 57 test_light.getState()["state"]["on"] = false;
  58 + prep_ret = {{{"success", {{"/lights/1/state/bri", 0}}}}};
  59 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
66 60 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(0, 4, test_light));
67 61  
  62 + prep_ret = {{{"success", {{"/lights/1/state/on", true}}}}, {{"success", {{"/lights/1/state/bri", 50}}}}};
  63 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
68 64 test_light.getState()["state"]["bri"] = 0;
69 65 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(50, 6, test_light));
70 66 test_light.getState()["state"]["on"] = true;
71 67 test_light.getState()["state"]["bri"] = 50;
  68 + // No request because state matches
72 69 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(50, 6, test_light));
73 70  
74   - prep_ret[2]["success"]["/lights/1/state/bri"] = 254;
75   - EXPECT_CALL(test_light, SendPutRequest(_, "/state", _)).Times(1).WillOnce(Return(prep_ret));
  71 + prep_ret[1]["success"]["/lights/1/state/bri"] = 254;
  72 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
76 73 test_light.getState()["state"]["on"] = false;
77 74 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(255, 6, test_light));
78 75 }
... ...
test/test_SimpleColorHueStrategy.cpp
... ... @@ -45,6 +45,8 @@ TEST(SimpleColorHueStrategy, setColorHue)
45 45 .WillRepeatedly(Return(nlohmann::json::object()));
46 46 MockHueLight test_light(handler);
47 47  
  48 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  49 +
48 50 nlohmann::json prep_ret;
49 51 prep_ret = nlohmann::json::array();
50 52 prep_ret[0] = nlohmann::json::object();
... ... @@ -56,7 +58,7 @@ TEST(SimpleColorHueStrategy, setColorHue)
56 58 prep_ret[2] = nlohmann::json::object();
57 59 prep_ret[2]["success"] = nlohmann::json::object();
58 60 prep_ret[2]["success"]["/lights/1/state/hue"] = 30500;
59   - EXPECT_CALL(test_light, SendPutRequest(_, "/state", _)).Times(1).WillOnce(Return(prep_ret));
  61 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
60 62  
61 63 test_light.getState()["state"]["on"] = true;
62 64 test_light.getState()["state"]["hue"] = 200;
... ... @@ -77,6 +79,8 @@ TEST(SimpleColorHueStrategy, setColorSaturation)
77 79 .WillRepeatedly(Return(nlohmann::json::object()));
78 80 MockHueLight test_light(handler);
79 81  
  82 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  83 +
80 84 nlohmann::json prep_ret;
81 85 prep_ret = nlohmann::json::array();
82 86 prep_ret[0] = nlohmann::json::object();
... ... @@ -88,7 +92,7 @@ TEST(SimpleColorHueStrategy, setColorSaturation)
88 92 prep_ret[2] = nlohmann::json::object();
89 93 prep_ret[2]["success"] = nlohmann::json::object();
90 94 prep_ret[2]["success"]["/lights/1/state/sat"] = 254;
91   - EXPECT_CALL(test_light, SendPutRequest(_, "/state", _)).Times(1).WillOnce(Return(prep_ret));
  95 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
92 96  
93 97 test_light.getState()["state"]["on"] = true;
94 98 test_light.getState()["state"]["sat"] = 100;
... ... @@ -109,6 +113,8 @@ TEST(SimpleColorHueStrategy, setColorHueSaturation)
109 113 .WillRepeatedly(Return(nlohmann::json::object()));
110 114 MockHueLight test_light(handler);
111 115  
  116 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  117 +
112 118 nlohmann::json prep_ret;
113 119 prep_ret = nlohmann::json::array();
114 120 prep_ret[0] = nlohmann::json::object();
... ... @@ -123,7 +129,7 @@ TEST(SimpleColorHueStrategy, setColorHueSaturation)
123 129 prep_ret[3] = nlohmann::json::object();
124 130 prep_ret[3]["success"] = nlohmann::json::object();
125 131 prep_ret[3]["success"]["/lights/1/state/sat"] = 254;
126   - EXPECT_CALL(test_light, SendPutRequest(_, "/state", _)).Times(1).WillOnce(Return(prep_ret));
  132 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
127 133  
128 134 test_light.getState()["state"]["on"] = true;
129 135 test_light.getState()["state"]["sat"] = 100;
... ... @@ -145,6 +151,8 @@ TEST(SimpleColorHueStrategy, setColorXY)
145 151 .WillRepeatedly(Return(nlohmann::json::object()));
146 152 MockHueLight test_light(handler);
147 153  
  154 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  155 +
148 156 nlohmann::json prep_ret;
149 157 prep_ret = nlohmann::json::array();
150 158 prep_ret[0] = nlohmann::json::object();
... ... @@ -157,7 +165,7 @@ TEST(SimpleColorHueStrategy, setColorXY)
157 165 prep_ret[2]["success"] = nlohmann::json::object();
158 166 prep_ret[2]["success"]["/lights/1/state/xy"][0] = 0.2355;
159 167 prep_ret[2]["success"]["/lights/1/state/xy"][1] = 0.1234;
160   - EXPECT_CALL(test_light, SendPutRequest(_, "/state", _)).Times(1).WillOnce(Return(prep_ret));
  168 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
161 169  
162 170 test_light.getState()["state"]["on"] = true;
163 171 test_light.getState()["state"]["xy"][0] = 0.1f;
... ... @@ -198,6 +206,8 @@ TEST(SimpleColorHueStrategy, setColorLoop)
198 206 .WillRepeatedly(Return(nlohmann::json::object()));
199 207 MockHueLight test_light(handler);
200 208  
  209 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  210 +
201 211 nlohmann::json prep_ret;
202 212 prep_ret = nlohmann::json::array();
203 213 prep_ret[0] = nlohmann::json::object();
... ... @@ -206,7 +216,7 @@ TEST(SimpleColorHueStrategy, setColorLoop)
206 216 prep_ret[1] = nlohmann::json::object();
207 217 prep_ret[1]["success"] = nlohmann::json::object();
208 218 prep_ret[1]["success"]["/lights/1/state/effect"] = "colorloop";
209   - EXPECT_CALL(test_light, SendPutRequest(_, "/state", _)).Times(1).WillOnce(Return(prep_ret));
  219 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
210 220  
211 221 test_light.getState()["state"]["on"] = true;
212 222 test_light.getState()["state"]["effect"] = "colorloop";
... ...
test/test_SimpleColorTemperatureStrategy.cpp
... ... @@ -46,6 +46,8 @@ TEST(SimpleColorTemperatureStrategy, setColorTemperature)
46 46 .WillRepeatedly(Return(nlohmann::json::object()));
47 47 MockHueLight test_light(handler);
48 48  
  49 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  50 +
49 51 nlohmann::json prep_ret;
50 52 prep_ret = nlohmann::json::array();
51 53 prep_ret[0] = nlohmann::json::object();
... ... @@ -57,21 +59,22 @@ TEST(SimpleColorTemperatureStrategy, setColorTemperature)
57 59 prep_ret[2] = nlohmann::json::object();
58 60 prep_ret[2]["success"] = nlohmann::json::object();
59 61 prep_ret[2]["success"]["/lights/1/state/ct"] = 155;
60   - EXPECT_CALL(test_light, SendPutRequest(_, "/state", _)).Times(1).WillOnce(Return(prep_ret));
  62 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
61 63  
62 64 test_light.getState()["state"]["on"] = true;
63 65 test_light.getState()["state"]["ct"] = 200;
  66 + test_light.getState()["state"]["colormode"] = "ct";
64 67 EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(200, 4, test_light));
65 68  
66 69 test_light.getState()["state"]["on"] = false;
67 70 EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(155, 6, test_light));
68 71  
69   - prep_ret[2]["success"]["/lights/1/state/ct"] = 153;
70   - EXPECT_CALL(test_light, SendPutRequest(_, "/state", _)).Times(1).WillOnce(Return(prep_ret));
  72 + prep_ret = {{{"success", {{"/lights/1/state/transitiontime", 6}}}}, {{"success", {{"/lights/1/state/ct", 153}}}}};
  73 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
71 74 EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(0, 6, test_light));
72 75  
73   - prep_ret[2]["success"]["/lights/1/state/ct"] = 500;
74   - EXPECT_CALL(test_light, SendPutRequest(_, "/state", _)).Times(1).WillOnce(Return(prep_ret));
  76 + prep_ret[1]["success"]["/lights/1/state/ct"] = 500;
  77 + EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
75 78 EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(600, 6, test_light));
76 79 }
77 80  
... ...