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,44 +28,12 @@
28 28
29 #include "APICache.h" 29 #include "APICache.h"
30 #include "HueCommandAPI.h" 30 #include "HueCommandAPI.h"
  31 +#include "StateTransaction.h"
31 32
32 #include "json/json.hpp" 33 #include "json/json.hpp"
33 34
34 namespace hueplusplus 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 class Group 37 class Group
70 { 38 {
71 public: 39 public:
include/hueplusplus/HueLight.h
@@ -30,6 +30,7 @@ @@ -30,6 +30,7 @@
30 #include "ColorHueStrategy.h" 30 #include "ColorHueStrategy.h"
31 #include "ColorTemperatureStrategy.h" 31 #include "ColorTemperatureStrategy.h"
32 #include "HueCommandAPI.h" 32 #include "HueCommandAPI.h"
  33 +#include "StateTransaction.h"
33 34
34 #include "json/json.hpp" 35 #include "json/json.hpp"
35 36
@@ -78,7 +79,7 @@ LLC020 // Hue Go, Color Gamut C, ECL @@ -78,7 +79,7 @@ LLC020 // Hue Go, Color Gamut C, ECL
78 };*/ 79 };*/
79 80
80 //! enum that specifies the color type of all HueLights 81 //! enum that specifies the color type of all HueLights
81 -enum ColorType 82 +enum class ColorType
82 { 83 {
83 UNDEFINED, //!< ColorType for this light is unknown or undefined 84 UNDEFINED, //!< ColorType for this light is unknown or undefined
84 NONE, //!< light has no specific ColorType 85 NONE, //!< light has no specific ColorType
@@ -676,6 +677,8 @@ public: @@ -676,6 +677,8 @@ public:
676 return false; 677 return false;
677 }; 678 };
678 679
  680 + virtual StateTransaction transaction();
  681 +
679 protected: 682 protected:
680 //! \brief Protected ctor that is used by \ref Hue class. 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 \ No newline at end of file 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,12 +66,22 @@ nlohmann::json safeGetMemberHelper(const nlohmann::json&amp; json, std::size_t index
66 66
67 //! \brief Function for validating that a request was executed correctly 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 //! \param request The request that was sent initially 70 //! \param request The request that was sent initially
70 //! \param reply The reply that was received 71 //! \param reply The reply that was received
71 -//! \param lightId The identifier of the light  
72 //! \return True if request was executed correctly 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 bool validateReplyForLight(const nlohmann::json& request, const nlohmann::json& reply, int lightId); 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 //! \brief Returns the object/array member or null if it does not exist 85 //! \brief Returns the object/array member or null if it does not exist
76 //! 86 //!
77 //! \param json The base json value 87 //! \param json The base json value
src/CMakeLists.txt
@@ -14,7 +14,7 @@ set(hueplusplus_SOURCES @@ -14,7 +14,7 @@ set(hueplusplus_SOURCES
14 SimpleColorTemperatureStrategy.cpp 14 SimpleColorTemperatureStrategy.cpp
15 UPnP.cpp 15 UPnP.cpp
16 Utils.cpp 16 Utils.cpp
17 -) 17 + StateTransaction.cpp)
18 18
19 # on windows we want to compile the WinHttpHandler 19 # on windows we want to compile the WinHttpHandler
20 if(WIN32) 20 if(WIN32)
src/ExtendedColorHueStrategy.cpp
@@ -200,8 +200,8 @@ bool ExtendedColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLigh @@ -200,8 +200,8 @@ bool ExtendedColorHueStrategy::alertRGB(uint8_t r, uint8_t g, uint8_t b, HueLigh
200 { 200 {
201 // Careful, only use state until any light function might refresh the value and invalidate the reference 201 // Careful, only use state until any light function might refresh the value and invalidate the reference
202 const nlohmann::json& state = light.state.GetValue()["state"]; 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 if (cType == "hs") 205 if (cType == "hs")
206 { 206 {
207 uint16_t oldHue = state["hue"].get<uint16_t>(); 207 uint16_t oldHue = state["hue"].get<uint16_t>();
src/Group.cpp
@@ -2,159 +2,35 @@ @@ -2,159 +2,35 @@
2 2
3 #include "hueplusplus/HueExceptionMacro.h" 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 : id(id), state("/groups/" + std::to_string(id), commands, refreshDuration), commands(commands) 8 : id(id), state("/groups/" + std::to_string(id), commands, refreshDuration), commands(commands)
133 { 9 {
134 state.Refresh(); 10 state.Refresh();
135 } 11 }
136 12
137 -void hueplusplus::Group::Refresh() 13 +void Group::Refresh()
138 { 14 {
139 state.Refresh(); 15 state.Refresh();
140 } 16 }
141 17
142 -int hueplusplus::Group::getId() const 18 +int Group::getId() const
143 { 19 {
144 return id; 20 return id;
145 } 21 }
146 22
147 -std::string hueplusplus::Group::getName() const 23 +std::string Group::getName() const
148 { 24 {
149 return state.GetValue().at("name").get<std::string>(); 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 return state.GetValue().at("type").get<std::string>(); 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 const nlohmann::json& lights = state.GetValue().at("lights"); 35 const nlohmann::json& lights = state.GetValue().at("lights");
160 std::vector<int> ids; 36 std::vector<int> ids;
@@ -166,13 +42,13 @@ std::vector&lt;int&gt; hueplusplus::Group::getLightIds() const @@ -166,13 +42,13 @@ std::vector&lt;int&gt; hueplusplus::Group::getLightIds() const
166 return ids; 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 nlohmann::json request = {{"name", name}}; 47 nlohmann::json request = {{"name", name}};
172 SendPutRequest(request, "", CURRENT_FILE_INFO); 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 nlohmann::json lights = nlohmann::json::array(); 53 nlohmann::json lights = nlohmann::json::array();
178 for (int id : ids) 54 for (int id : ids)
@@ -182,90 +58,91 @@ void hueplusplus::Group::setLights(const std::vector&lt;int&gt;&amp; ids) @@ -182,90 +58,91 @@ void hueplusplus::Group::setLights(const std::vector&lt;int&gt;&amp; ids)
182 SendPutRequest({{"lights", lights}}, "", CURRENT_FILE_INFO); 58 SendPutRequest({{"lights", lights}}, "", CURRENT_FILE_INFO);
183 } 59 }
184 60
185 -bool hueplusplus::Group::getAllOn() 61 +bool Group::getAllOn()
186 { 62 {
187 return state.GetValue().at("state").at("all_on").get<bool>(); 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 return state.GetValue().at("state").at("all_on").get<bool>(); 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 return state.GetValue().at("state").at("any_on").get<bool>(); 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 return state.GetValue().at("state").at("any_on").get<bool>(); 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 return state.GetValue().at("action").at("on").get<bool>(); 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 return state.GetValue().at("action").at("on").get<bool>(); 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 const nlohmann::json& action = state.GetValue().at("action"); 90 const nlohmann::json& action = state.GetValue().at("action");
215 91
216 return std::make_pair(action.at("hue").get<int>(), action.at("sat").get<int>()); 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 const nlohmann::json& action = state.GetValue().at("action"); 96 const nlohmann::json& action = state.GetValue().at("action");
221 97
222 return std::make_pair(action.at("hue").get<int>(), action.at("sat").get<int>()); 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 return state.GetValue().at("action").at("bri").get<int>(); 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 return state.GetValue().at("action").at("bri").get<int>(); 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 return state.GetValue().at("action").at("ct").get<int>(); 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 return state.GetValue().at("action").at("ct").get<int>(); 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 const nlohmann::json& xy = state.GetValue().at("action").at("xy"); 121 const nlohmann::json& xy = state.GetValue().at("action").at("xy");
246 return std::pair<float, float>(xy[0].get<float>(), xy[1].get<float>()); 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 const nlohmann::json& xy = state.GetValue().at("action").at("xy"); 126 const nlohmann::json& xy = state.GetValue().at("action").at("xy");
251 return std::pair<float, float>(xy[0].get<float>(), xy[1].get<float>()); 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 return state.GetValue().at("action").at("colormode").get<std::string>(); 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 return state.GetValue().at("action").at("colormode").get<std::string>(); 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 nlohmann::json request = {{"on", on}}; 147 nlohmann::json request = {{"on", on}};
271 if (transition != 4) 148 if (transition != 4)
@@ -275,83 +152,83 @@ void hueplusplus::Group::setOn(bool on, uint8_t transition) @@ -275,83 +152,83 @@ void hueplusplus::Group::setOn(bool on, uint8_t transition)
275 SendPutRequest(request, "/action", CURRENT_FILE_INFO); 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 transaction().setBrightness(brightness).setTransition(transition).commit(); 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 transaction().setColorHueSaturation(hue, saturation).setTransition(transition).commit(); 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 transaction().setColorXY(x, y).setTransition(transition).commit(); 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 transaction().setColorTemperature(mired).setTransition(transition).commit(); 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 transaction().setColorLoop(on).setTransition(transition); 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 transaction().incrementBrightness(increment).setTransition(transition).commit(); 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 transaction().incrementSaturation(increment).setTransition(transition).commit(); 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 transaction().incrementHue(increment).setTransition(transition).commit(); 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 transaction().incrementColorTemperature(increment).setTransition(transition).commit(); 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 transaction().incrementColorXY(incX, incY).setTransition(transition).commit(); 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 return commands.PUTRequest("/groups/" + std::to_string(id) + subPath, request, std::move(fileInfo)); 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 return state.GetValue().at("class").get<std::string>(); 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 SendPutRequest({{"class", type}}, "", CURRENT_FILE_INFO); 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 return state.GetValue().at("modelid").get<std::string>(); 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 return state.GetValue().at("uniqueid").get<std::string>(); 232 return state.GetValue().at("uniqueid").get<std::string>();
357 } 233 }
  234 +} // namespace hueplusplus
src/HueLight.cpp
@@ -34,60 +34,22 @@ namespace hueplusplus @@ -34,60 +34,22 @@ namespace hueplusplus
34 { 34 {
35 bool HueLight::On(uint8_t transition) 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 bool HueLight::Off(uint8_t transition) 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 bool HueLight::isOn() 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 bool HueLight::isOn() const 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 int HueLight::getId() const 55 int HueLight::getId() const
@@ -173,12 +135,12 @@ unsigned int HueLight::MiredToKelvin(unsigned int mired) const @@ -173,12 +135,12 @@ unsigned int HueLight::MiredToKelvin(unsigned int mired) const
173 135
174 bool HueLight::alert() 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 HueLight::HueLight(int id, const HueCommandAPI& commands) : HueLight(id, commands, nullptr, nullptr, nullptr) {} 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,12 +149,12 @@ HueLight::HueLight(int id, const HueCommandAPI&amp; commands, std::shared_ptr&lt;const
187 std::shared_ptr<const ColorTemperatureStrategy> colorTempStrategy, 149 std::shared_ptr<const ColorTemperatureStrategy> colorTempStrategy,
188 std::shared_ptr<const ColorHueStrategy> colorHueStrategy, std::chrono::steady_clock::duration refreshDuration) 150 std::shared_ptr<const ColorHueStrategy> colorHueStrategy, std::chrono::steady_clock::duration refreshDuration)
189 : id(id), 151 : id(id),
  152 + state("/lights/" + std::to_string(id), commands, refreshDuration),
  153 + colorType(ColorType::NONE),
190 brightnessStrategy(std::move(brightnessStrategy)), 154 brightnessStrategy(std::move(brightnessStrategy)),
191 colorTemperatureStrategy(std::move(colorTempStrategy)), 155 colorTemperatureStrategy(std::move(colorTempStrategy)),
192 colorHueStrategy(std::move(colorHueStrategy)), 156 colorHueStrategy(std::move(colorHueStrategy)),
193 - commands(commands),  
194 - state("/lights/" + std::to_string(id), commands, refreshDuration)  
195 - 157 + commands(commands)
196 { 158 {
197 state.Refresh(); 159 state.Refresh();
198 } 160 }
src/SimpleBrightnessStrategy.cpp
@@ -34,49 +34,7 @@ namespace hueplusplus @@ -34,49 +34,7 @@ namespace hueplusplus
34 bool SimpleBrightnessStrategy::setBrightness(unsigned int bri, uint8_t transition, HueLight& light) const 34 bool SimpleBrightnessStrategy::setBrightness(unsigned int bri, uint8_t transition, HueLight& light) const
35 { 35 {
36 // Careful, only use state until any light function might refresh the value and invalidate the reference 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 unsigned int SimpleBrightnessStrategy::getBrightness(HueLight& light) const 40 unsigned int SimpleBrightnessStrategy::getBrightness(HueLight& light) const
src/SimpleColorHueStrategy.cpp
@@ -34,140 +34,22 @@ namespace hueplusplus @@ -34,140 +34,22 @@ namespace hueplusplus
34 { 34 {
35 bool SimpleColorHueStrategy::setColorHue(uint16_t hue, uint8_t transition, HueLight& light) const 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 bool SimpleColorHueStrategy::setColorSaturation(uint8_t sat, uint8_t transition, HueLight& light) const 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 bool SimpleColorHueStrategy::setColorHueSaturation(uint16_t hue, uint8_t sat, uint8_t transition, HueLight& light) const 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 bool SimpleColorHueStrategy::setColorXY(float x, float y, uint8_t transition, HueLight& light) const 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 bool SimpleColorHueStrategy::setColorRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t transition, HueLight& light) const 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,30 +80,7 @@ bool SimpleColorHueStrategy::setColorRGB(uint8_t r, uint8_t g, uint8_t b, uint8_
198 80
199 bool SimpleColorHueStrategy::setColorLoop(bool on, HueLight& light) const 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 bool SimpleColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, HueLight& light) const 86 bool SimpleColorHueStrategy::alertHueSaturation(uint16_t hue, uint8_t sat, HueLight& light) const
src/SimpleColorTemperatureStrategy.cpp
@@ -34,40 +34,7 @@ namespace hueplusplus @@ -34,40 +34,7 @@ namespace hueplusplus
34 { 34 {
35 bool SimpleColorTemperatureStrategy::setColorTemperature(unsigned int mired, uint8_t transition, HueLight& light) const 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 bool SimpleColorTemperatureStrategy::alertTemperature(unsigned int mired, HueLight& light) const 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 \ No newline at end of file 200 \ No newline at end of file
src/Utils.cpp
@@ -28,10 +28,14 @@ namespace hueplusplus @@ -28,10 +28,14 @@ namespace hueplusplus
28 { 28 {
29 namespace utils 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 bool success = false; 38 bool success = false;
34 - std::string path = "/lights/" + std::to_string(lightId) + "/state/";  
35 for (auto it = reply.begin(); it != reply.end(); ++it) 39 for (auto it = reply.begin(); it != reply.end(); ++it)
36 { 40 {
37 success = it.value().count("success"); 41 success = it.value().count("success");
@@ -42,9 +46,9 @@ bool validateReplyForLight(const nlohmann::json&amp; request, const nlohmann::json&amp; @@ -42,9 +46,9 @@ bool validateReplyForLight(const nlohmann::json&amp; request, const nlohmann::json&amp;
42 for (auto successIt = successObject.begin(); successIt != successObject.end(); ++successIt) 46 for (auto successIt = successObject.begin(); successIt != successObject.end(); ++successIt)
43 { 47 {
44 const std::string successPath = successIt.key(); 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 auto requestIt = request.find(valueKey); 52 auto requestIt = request.find(valueKey);
49 success = requestIt != request.end(); 53 success = requestIt != request.end();
50 if (success) 54 if (success)
@@ -58,7 +62,8 @@ bool validateReplyForLight(const nlohmann::json&amp; request, const nlohmann::json&amp; @@ -58,7 +62,8 @@ bool validateReplyForLight(const nlohmann::json&amp; request, const nlohmann::json&amp;
58 } 62 }
59 else 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 if (!success) 68 if (!success)
64 { 69 {
@@ -80,5 +85,10 @@ bool validateReplyForLight(const nlohmann::json&amp; request, const nlohmann::json&amp; @@ -80,5 +85,10 @@ bool validateReplyForLight(const nlohmann::json&amp; request, const nlohmann::json&amp;
80 } 85 }
81 return success; 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 } // namespace utils 93 } // namespace utils
84 } // namespace hueplusplus 94 } // namespace hueplusplus
test/CMakeLists.txt
@@ -70,6 +70,9 @@ add_custom_target(&quot;unittest&quot; @@ -70,6 +70,9 @@ add_custom_target(&quot;unittest&quot;
70 find_program( GCOV_PATH gcov ) 70 find_program( GCOV_PATH gcov )
71 find_program( LCOV_PATH lcov ) 71 find_program( LCOV_PATH lcov )
72 72
  73 +mark_as_advanced(GCOV_PATH)
  74 +mark_as_advanced(LCOV_PATH)
  75 +
73 if(LCOV_PATH AND GCOV_PATH) 76 if(LCOV_PATH AND GCOV_PATH)
74 # GCov 77 # GCov
75 include(CodeCoverage.cmake) 78 include(CodeCoverage.cmake)
test/test_HueLight.cpp
@@ -69,7 +69,7 @@ protected: @@ -69,7 +69,7 @@ protected:
69 hue_bridge_state["lights"]["2"] = nlohmann::json::object(); 69 hue_bridge_state["lights"]["2"] = nlohmann::json::object();
70 hue_bridge_state["lights"]["2"]["state"] = nlohmann::json::object(); 70 hue_bridge_state["lights"]["2"]["state"] = nlohmann::json::object();
71 hue_bridge_state["lights"]["2"]["state"]["on"] = false; 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 hue_bridge_state["lights"]["2"]["state"]["ct"] = 366; 73 hue_bridge_state["lights"]["2"]["state"]["ct"] = 366;
74 hue_bridge_state["lights"]["2"]["state"]["hue"] = 123456; 74 hue_bridge_state["lights"]["2"]["state"]["hue"] = 123456;
75 hue_bridge_state["lights"]["2"]["state"]["sat"] = 123; 75 hue_bridge_state["lights"]["2"]["state"]["sat"] = 123;
@@ -514,7 +514,7 @@ TEST_F(HueLightTest, setBrightness) @@ -514,7 +514,7 @@ TEST_F(HueLightTest, setBrightness)
514 prep_ret[1]["success"]["/lights/3/state/on"] = true; 514 prep_ret[1]["success"]["/lights/3/state/on"] = true;
515 prep_ret[2] = nlohmann::json::object(); 515 prep_ret[2] = nlohmann::json::object();
516 prep_ret[2]["success"] = nlohmann::json::object(); 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 EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80)) 518 EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
519 .Times(1) 519 .Times(1)
520 .WillOnce(Return(prep_ret)); 520 .WillOnce(Return(prep_ret));
@@ -525,7 +525,7 @@ TEST_F(HueLightTest, setBrightness) @@ -525,7 +525,7 @@ TEST_F(HueLightTest, setBrightness)
525 525
526 EXPECT_EQ(false, test_light_1.setBrightness(200)); 526 EXPECT_EQ(false, test_light_1.setBrightness(200));
527 EXPECT_EQ(true, test_light_2.setBrightness(0, 2)); 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 TEST_F(HueLightTest, getBrightness) 531 TEST_F(HueLightTest, getBrightness)
@@ -538,10 +538,10 @@ TEST_F(HueLightTest, getBrightness) @@ -538,10 +538,10 @@ TEST_F(HueLightTest, getBrightness)
538 HueLight test_light_3 = test_bridge.getLight(3); 538 HueLight test_light_3 = test_bridge.getLight(3);
539 539
540 EXPECT_EQ(254, ctest_light_1.getBrightness()); 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 EXPECT_EQ(254, ctest_light_3.getBrightness()); 542 EXPECT_EQ(254, ctest_light_3.getBrightness());
543 EXPECT_EQ(254, test_light_1.getBrightness()); 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 EXPECT_EQ(254, test_light_3.getBrightness()); 545 EXPECT_EQ(254, test_light_3.getBrightness());
546 } 546 }
547 547
test/test_SimpleBrightnessStrategy.cpp
@@ -46,33 +46,30 @@ TEST(SimpleBrightnessStrategy, setBrightness) @@ -46,33 +46,30 @@ TEST(SimpleBrightnessStrategy, setBrightness)
46 .WillRepeatedly(Return(nlohmann::json::object())); 46 .WillRepeatedly(Return(nlohmann::json::object()));
47 MockHueLight test_light(handler); 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 test_light.getState()["state"]["on"] = true; 54 test_light.getState()["state"]["on"] = true;
64 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(0, 4, test_light)); 55 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(0, 4, test_light));
  56 + // Only set brightness, already off
65 test_light.getState()["state"]["on"] = false; 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 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(0, 4, test_light)); 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 test_light.getState()["state"]["bri"] = 0; 64 test_light.getState()["state"]["bri"] = 0;
69 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(50, 6, test_light)); 65 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(50, 6, test_light));
70 test_light.getState()["state"]["on"] = true; 66 test_light.getState()["state"]["on"] = true;
71 test_light.getState()["state"]["bri"] = 50; 67 test_light.getState()["state"]["bri"] = 50;
  68 + // No request because state matches
72 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(50, 6, test_light)); 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 test_light.getState()["state"]["on"] = false; 73 test_light.getState()["state"]["on"] = false;
77 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(255, 6, test_light)); 74 EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(255, 6, test_light));
78 } 75 }
test/test_SimpleColorHueStrategy.cpp
@@ -45,6 +45,8 @@ TEST(SimpleColorHueStrategy, setColorHue) @@ -45,6 +45,8 @@ TEST(SimpleColorHueStrategy, setColorHue)
45 .WillRepeatedly(Return(nlohmann::json::object())); 45 .WillRepeatedly(Return(nlohmann::json::object()));
46 MockHueLight test_light(handler); 46 MockHueLight test_light(handler);
47 47
  48 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  49 +
48 nlohmann::json prep_ret; 50 nlohmann::json prep_ret;
49 prep_ret = nlohmann::json::array(); 51 prep_ret = nlohmann::json::array();
50 prep_ret[0] = nlohmann::json::object(); 52 prep_ret[0] = nlohmann::json::object();
@@ -56,7 +58,7 @@ TEST(SimpleColorHueStrategy, setColorHue) @@ -56,7 +58,7 @@ TEST(SimpleColorHueStrategy, setColorHue)
56 prep_ret[2] = nlohmann::json::object(); 58 prep_ret[2] = nlohmann::json::object();
57 prep_ret[2]["success"] = nlohmann::json::object(); 59 prep_ret[2]["success"] = nlohmann::json::object();
58 prep_ret[2]["success"]["/lights/1/state/hue"] = 30500; 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 test_light.getState()["state"]["on"] = true; 63 test_light.getState()["state"]["on"] = true;
62 test_light.getState()["state"]["hue"] = 200; 64 test_light.getState()["state"]["hue"] = 200;
@@ -77,6 +79,8 @@ TEST(SimpleColorHueStrategy, setColorSaturation) @@ -77,6 +79,8 @@ TEST(SimpleColorHueStrategy, setColorSaturation)
77 .WillRepeatedly(Return(nlohmann::json::object())); 79 .WillRepeatedly(Return(nlohmann::json::object()));
78 MockHueLight test_light(handler); 80 MockHueLight test_light(handler);
79 81
  82 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  83 +
80 nlohmann::json prep_ret; 84 nlohmann::json prep_ret;
81 prep_ret = nlohmann::json::array(); 85 prep_ret = nlohmann::json::array();
82 prep_ret[0] = nlohmann::json::object(); 86 prep_ret[0] = nlohmann::json::object();
@@ -88,7 +92,7 @@ TEST(SimpleColorHueStrategy, setColorSaturation) @@ -88,7 +92,7 @@ TEST(SimpleColorHueStrategy, setColorSaturation)
88 prep_ret[2] = nlohmann::json::object(); 92 prep_ret[2] = nlohmann::json::object();
89 prep_ret[2]["success"] = nlohmann::json::object(); 93 prep_ret[2]["success"] = nlohmann::json::object();
90 prep_ret[2]["success"]["/lights/1/state/sat"] = 254; 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 test_light.getState()["state"]["on"] = true; 97 test_light.getState()["state"]["on"] = true;
94 test_light.getState()["state"]["sat"] = 100; 98 test_light.getState()["state"]["sat"] = 100;
@@ -109,6 +113,8 @@ TEST(SimpleColorHueStrategy, setColorHueSaturation) @@ -109,6 +113,8 @@ TEST(SimpleColorHueStrategy, setColorHueSaturation)
109 .WillRepeatedly(Return(nlohmann::json::object())); 113 .WillRepeatedly(Return(nlohmann::json::object()));
110 MockHueLight test_light(handler); 114 MockHueLight test_light(handler);
111 115
  116 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  117 +
112 nlohmann::json prep_ret; 118 nlohmann::json prep_ret;
113 prep_ret = nlohmann::json::array(); 119 prep_ret = nlohmann::json::array();
114 prep_ret[0] = nlohmann::json::object(); 120 prep_ret[0] = nlohmann::json::object();
@@ -123,7 +129,7 @@ TEST(SimpleColorHueStrategy, setColorHueSaturation) @@ -123,7 +129,7 @@ TEST(SimpleColorHueStrategy, setColorHueSaturation)
123 prep_ret[3] = nlohmann::json::object(); 129 prep_ret[3] = nlohmann::json::object();
124 prep_ret[3]["success"] = nlohmann::json::object(); 130 prep_ret[3]["success"] = nlohmann::json::object();
125 prep_ret[3]["success"]["/lights/1/state/sat"] = 254; 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 test_light.getState()["state"]["on"] = true; 134 test_light.getState()["state"]["on"] = true;
129 test_light.getState()["state"]["sat"] = 100; 135 test_light.getState()["state"]["sat"] = 100;
@@ -145,6 +151,8 @@ TEST(SimpleColorHueStrategy, setColorXY) @@ -145,6 +151,8 @@ TEST(SimpleColorHueStrategy, setColorXY)
145 .WillRepeatedly(Return(nlohmann::json::object())); 151 .WillRepeatedly(Return(nlohmann::json::object()));
146 MockHueLight test_light(handler); 152 MockHueLight test_light(handler);
147 153
  154 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  155 +
148 nlohmann::json prep_ret; 156 nlohmann::json prep_ret;
149 prep_ret = nlohmann::json::array(); 157 prep_ret = nlohmann::json::array();
150 prep_ret[0] = nlohmann::json::object(); 158 prep_ret[0] = nlohmann::json::object();
@@ -157,7 +165,7 @@ TEST(SimpleColorHueStrategy, setColorXY) @@ -157,7 +165,7 @@ TEST(SimpleColorHueStrategy, setColorXY)
157 prep_ret[2]["success"] = nlohmann::json::object(); 165 prep_ret[2]["success"] = nlohmann::json::object();
158 prep_ret[2]["success"]["/lights/1/state/xy"][0] = 0.2355; 166 prep_ret[2]["success"]["/lights/1/state/xy"][0] = 0.2355;
159 prep_ret[2]["success"]["/lights/1/state/xy"][1] = 0.1234; 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 test_light.getState()["state"]["on"] = true; 170 test_light.getState()["state"]["on"] = true;
163 test_light.getState()["state"]["xy"][0] = 0.1f; 171 test_light.getState()["state"]["xy"][0] = 0.1f;
@@ -198,6 +206,8 @@ TEST(SimpleColorHueStrategy, setColorLoop) @@ -198,6 +206,8 @@ TEST(SimpleColorHueStrategy, setColorLoop)
198 .WillRepeatedly(Return(nlohmann::json::object())); 206 .WillRepeatedly(Return(nlohmann::json::object()));
199 MockHueLight test_light(handler); 207 MockHueLight test_light(handler);
200 208
  209 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  210 +
201 nlohmann::json prep_ret; 211 nlohmann::json prep_ret;
202 prep_ret = nlohmann::json::array(); 212 prep_ret = nlohmann::json::array();
203 prep_ret[0] = nlohmann::json::object(); 213 prep_ret[0] = nlohmann::json::object();
@@ -206,7 +216,7 @@ TEST(SimpleColorHueStrategy, setColorLoop) @@ -206,7 +216,7 @@ TEST(SimpleColorHueStrategy, setColorLoop)
206 prep_ret[1] = nlohmann::json::object(); 216 prep_ret[1] = nlohmann::json::object();
207 prep_ret[1]["success"] = nlohmann::json::object(); 217 prep_ret[1]["success"] = nlohmann::json::object();
208 prep_ret[1]["success"]["/lights/1/state/effect"] = "colorloop"; 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 test_light.getState()["state"]["on"] = true; 221 test_light.getState()["state"]["on"] = true;
212 test_light.getState()["state"]["effect"] = "colorloop"; 222 test_light.getState()["state"]["effect"] = "colorloop";
test/test_SimpleColorTemperatureStrategy.cpp
@@ -46,6 +46,8 @@ TEST(SimpleColorTemperatureStrategy, setColorTemperature) @@ -46,6 +46,8 @@ TEST(SimpleColorTemperatureStrategy, setColorTemperature)
46 .WillRepeatedly(Return(nlohmann::json::object())); 46 .WillRepeatedly(Return(nlohmann::json::object()));
47 MockHueLight test_light(handler); 47 MockHueLight test_light(handler);
48 48
  49 + const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
  50 +
49 nlohmann::json prep_ret; 51 nlohmann::json prep_ret;
50 prep_ret = nlohmann::json::array(); 52 prep_ret = nlohmann::json::array();
51 prep_ret[0] = nlohmann::json::object(); 53 prep_ret[0] = nlohmann::json::object();
@@ -57,21 +59,22 @@ TEST(SimpleColorTemperatureStrategy, setColorTemperature) @@ -57,21 +59,22 @@ TEST(SimpleColorTemperatureStrategy, setColorTemperature)
57 prep_ret[2] = nlohmann::json::object(); 59 prep_ret[2] = nlohmann::json::object();
58 prep_ret[2]["success"] = nlohmann::json::object(); 60 prep_ret[2]["success"] = nlohmann::json::object();
59 prep_ret[2]["success"]["/lights/1/state/ct"] = 155; 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 test_light.getState()["state"]["on"] = true; 64 test_light.getState()["state"]["on"] = true;
63 test_light.getState()["state"]["ct"] = 200; 65 test_light.getState()["state"]["ct"] = 200;
  66 + test_light.getState()["state"]["colormode"] = "ct";
64 EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(200, 4, test_light)); 67 EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(200, 4, test_light));
65 68
66 test_light.getState()["state"]["on"] = false; 69 test_light.getState()["state"]["on"] = false;
67 EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(155, 6, test_light)); 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 EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(0, 6, test_light)); 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 EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(600, 6, test_light)); 78 EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(600, 6, test_light));
76 } 79 }
77 80