Commit 8bfb374147baa3244aa40045dc2d7a46c0ec1275

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent 6e00e6d5

Implement HueLightFactory::getColorType, fix tests.

The color type is determined using the capabilities field on the light state. If that is not present, the hardcoded types are used.
include/hueplusplus/HueDeviceTypes.h
@@ -33,12 +33,16 @@ namespace hueplusplus @@ -33,12 +33,16 @@ namespace hueplusplus
33 class HueLightFactory 33 class HueLightFactory
34 { 34 {
35 public: 35 public:
36 - HueLightFactory(const HueCommandAPI& commands); 36 + HueLightFactory(const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration);
37 37
38 HueLight createLight(const nlohmann::json& lightState, int id); 38 HueLight createLight(const nlohmann::json& lightState, int id);
39 39
40 private: 40 private:
  41 + ColorType getColorType(const nlohmann::json& lightState, bool hasCt) const;
  42 +
  43 +private:
41 HueCommandAPI commands; 44 HueCommandAPI commands;
  45 + std::chrono::steady_clock::duration refreshDuration;
42 std::shared_ptr<BrightnessStrategy> simpleBrightness; 46 std::shared_ptr<BrightnessStrategy> simpleBrightness;
43 std::shared_ptr<ColorTemperatureStrategy> simpleColorTemperature; 47 std::shared_ptr<ColorTemperatureStrategy> simpleColorTemperature;
44 std::shared_ptr<ColorTemperatureStrategy> extendedColorTemperature; 48 std::shared_ptr<ColorTemperatureStrategy> extendedColorTemperature;
include/hueplusplus/HueLight.h
@@ -118,7 +118,13 @@ public: @@ -118,7 +118,13 @@ public:
118 118
119 //! \brief Const function that returns the light type 119 //! \brief Const function that returns the light type
120 //! 120 //!
  121 + //! The type determines which functions the light has.
121 //! \return String containing the type 122 //! \return String containing the type
  123 + //! - "On/Off light": on/off
  124 + //! - "Dimmable light": on/off, brightness
  125 + //! - "Color light": on/off, brightness, color hue/sat/xy
  126 + //! - "Color temperature light": on/off, brightness, color temperature
  127 + //! - "Extended color light": on/off, brightness, color temperature, color hue/sat/xy
122 virtual std::string getType() const; 128 virtual std::string getType() const;
123 129
124 //! \brief Function that returns the name of the light. 130 //! \brief Function that returns the name of the light.
src/Hue.cpp
@@ -137,7 +137,7 @@ Hue::Hue(const std::string&amp; ip, const int port, const std::string&amp; username, @@ -137,7 +137,7 @@ Hue::Hue(const std::string&amp; ip, const int port, const std::string&amp; username,
137 http_handler(std::move(handler)), 137 http_handler(std::move(handler)),
138 commands(ip, port, username, http_handler), 138 commands(ip, port, username, http_handler),
139 stateCache("", commands, refreshDuration), 139 stateCache("", commands, refreshDuration),
140 - lightFactory(commands) 140 + lightFactory(commands, refreshDuration)
141 {} 141 {}
142 142
143 std::string Hue::getBridgeIP() 143 std::string Hue::getBridgeIP()
@@ -179,9 +179,7 @@ std::string Hue::requestUsername() @@ -179,9 +179,7 @@ std::string Hue::requestUsername()
179 // [{"success":{"username": "<username>"}}] 179 // [{"success":{"username": "<username>"}}]
180 username = jsonUser.get<std::string>(); 180 username = jsonUser.get<std::string>();
181 // Update commands with new username and ip 181 // Update commands with new username and ip
182 - commands = HueCommandAPI(ip, port, username, http_handler);  
183 - stateCache = APICache("", commands, stateCache.getRefreshDuration());  
184 - lightFactory = HueLightFactory(commands); 182 + setHttpHandler(http_handler);
185 std::cout << "Success! Link button was pressed!\n"; 183 std::cout << "Success! Link button was pressed!\n";
186 std::cout << "Username is \"" << username << "\"\n"; 184 std::cout << "Username is \"" << username << "\"\n";
187 break; 185 break;
@@ -523,6 +521,6 @@ void Hue::setHttpHandler(std::shared_ptr&lt;const IHttpHandler&gt; handler) @@ -523,6 +521,6 @@ void Hue::setHttpHandler(std::shared_ptr&lt;const IHttpHandler&gt; handler)
523 http_handler = handler; 521 http_handler = handler;
524 commands = HueCommandAPI(ip, port, username, handler); 522 commands = HueCommandAPI(ip, port, username, handler);
525 stateCache = APICache("", commands, stateCache.getRefreshDuration()); 523 stateCache = APICache("", commands, stateCache.getRefreshDuration());
526 - lightFactory = HueLightFactory(commands); 524 + lightFactory = HueLightFactory(commands, stateCache.getRefreshDuration());
527 } 525 }
528 } // namespace hueplusplus 526 } // namespace hueplusplus
src/HueDeviceTypes.cpp
@@ -31,6 +31,7 @@ @@ -31,6 +31,7 @@
31 #include "hueplusplus/SimpleBrightnessStrategy.h" 31 #include "hueplusplus/SimpleBrightnessStrategy.h"
32 #include "hueplusplus/SimpleColorHueStrategy.h" 32 #include "hueplusplus/SimpleColorHueStrategy.h"
33 #include "hueplusplus/SimpleColorTemperatureStrategy.h" 33 #include "hueplusplus/SimpleColorTemperatureStrategy.h"
  34 +#include "hueplusplus/Utils.h"
34 35
35 namespace hueplusplus 36 namespace hueplusplus
36 { 37 {
@@ -56,32 +57,11 @@ const std::set&lt;std::string&gt;&amp; getGamutATypes() @@ -56,32 +57,11 @@ const std::set&lt;std::string&gt;&amp; getGamutATypes()
56 = {"LST001", "LLC005", "LLC006", "LLC007", "LLC010", "LLC011", "LLC012", "LLC013", "LLC014"}; 57 = {"LST001", "LLC005", "LLC006", "LLC007", "LLC010", "LLC011", "LLC012", "LLC013", "LLC014"};
57 return c_EXTENDEDCOLORLIGHT_GAMUTA_TYPES; 58 return c_EXTENDEDCOLORLIGHT_GAMUTA_TYPES;
58 } 59 }
59 -  
60 -const std::set<std::string>& getNoColorTypes()  
61 -{  
62 - static const std::set<std::string> c_DIMMABLELIGHT_NO_COLOR_TYPES  
63 - = {"LWB004", "LWB006", "LWB007", "LWB010", "LWB014", "LDF001", "LDF002", "LDD001", "LDD002", "MWM001"};  
64 - return c_DIMMABLELIGHT_NO_COLOR_TYPES;  
65 -}  
66 -  
67 -const std::set<std::string>& getNonDimmableTypes()  
68 -{  
69 - static const std::set<std::string> c_NON_DIMMABLE_TYPES = {"Plug 01"};  
70 - return c_NON_DIMMABLE_TYPES;  
71 -}  
72 -  
73 -const std::set<std::string>& getTemperatureLightTypes()  
74 -{  
75 - static const std::set<std::string> c_TEMPERATURELIGHT_TYPES  
76 - = {"LLM010", "LLM011", "LLM012", "LTW001", "LTW004", "LTW010", "LTW011", "LTW012", "LTW013", "LTW014", "LTW015",  
77 - "LTP001", "LTP002", "LTP003", "LTP004", "LTP005", "LTD003", "LTF001", "LTF002", "LTC001", "LTC002",  
78 - "LTC003", "LTC004", "LTC011", "LTC012", "LTD001", "LTD002", "LFF001", "LTT001", "LDT001"};  
79 - return c_TEMPERATURELIGHT_TYPES;  
80 -}  
81 } // namespace 60 } // namespace
82 61
83 -HueLightFactory::HueLightFactory(const HueCommandAPI& commands) 62 +HueLightFactory::HueLightFactory(const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration)
84 : commands(commands), 63 : commands(commands),
  64 + refreshDuration(refreshDuration),
85 simpleBrightness(std::make_shared<SimpleBrightnessStrategy>()), 65 simpleBrightness(std::make_shared<SimpleBrightnessStrategy>()),
86 simpleColorHue(std::make_shared<SimpleColorHueStrategy>()), 66 simpleColorHue(std::make_shared<SimpleColorHueStrategy>()),
87 extendedColorHue(std::make_shared<ExtendedColorHueStrategy>()), 67 extendedColorHue(std::make_shared<ExtendedColorHueStrategy>()),
@@ -97,35 +77,81 @@ HueLight HueLightFactory::createLight(const nlohmann::json&amp; lightState, int id) @@ -97,35 +77,81 @@ HueLight HueLightFactory::createLight(const nlohmann::json&amp; lightState, int id)
97 77
98 if (type == "on/off light") 78 if (type == "on/off light")
99 { 79 {
100 - HueLight light(id, commands, nullptr, nullptr, nullptr); 80 + HueLight light(id, commands, nullptr, nullptr, nullptr, refreshDuration);
101 light.colorType = ColorType::NONE; 81 light.colorType = ColorType::NONE;
102 return light; 82 return light;
103 } 83 }
104 else if (type == "dimmable light") 84 else if (type == "dimmable light")
105 { 85 {
106 - HueLight light(id, commands, simpleBrightness, nullptr, nullptr); 86 + HueLight light(id, commands, simpleBrightness, nullptr, nullptr, refreshDuration);
107 light.colorType = ColorType::NONE; 87 light.colorType = ColorType::NONE;
108 return light; 88 return light;
109 } 89 }
110 else if (type == "color temperature light") 90 else if (type == "color temperature light")
111 { 91 {
112 - HueLight light(id, commands, simpleBrightness, simpleColorTemperature, nullptr); 92 + HueLight light(id, commands, simpleBrightness, simpleColorTemperature, nullptr, refreshDuration);
113 light.colorType = ColorType::TEMPERATURE; 93 light.colorType = ColorType::TEMPERATURE;
114 return light; 94 return light;
115 } 95 }
116 else if (type == "color light") 96 else if (type == "color light")
117 { 97 {
118 - HueLight light(id, commands, simpleBrightness, nullptr, simpleColorHue);  
119 - light.colorType = ColorType::GAMUT_A; // getColorType(state); 98 + HueLight light(id, commands, simpleBrightness, nullptr, simpleColorHue, refreshDuration);
  99 + light.colorType = getColorType(lightState, false);
120 return light; 100 return light;
121 } 101 }
122 else if (type == "extended color light") 102 else if (type == "extended color light")
123 { 103 {
124 - HueLight light(id, commands, simpleBrightness, extendedColorTemperature, extendedColorHue);  
125 - light.colorType = ColorType::GAMUT_B_TEMPERATURE; // getColorType(state); 104 + HueLight light(id, commands, simpleBrightness, extendedColorTemperature, extendedColorHue, refreshDuration);
  105 + light.colorType = getColorType(lightState, true);
126 return light; 106 return light;
127 } 107 }
128 std::cerr << "Could not determine HueLight type:" << type << "!\n"; 108 std::cerr << "Could not determine HueLight type:" << type << "!\n";
129 throw HueException(CURRENT_FILE_INFO, "Could not determine HueLight type!"); 109 throw HueException(CURRENT_FILE_INFO, "Could not determine HueLight type!");
130 } 110 }
  111 +
  112 +ColorType HueLightFactory::getColorType(const nlohmann::json& lightState, bool hasCt) const
  113 +{
  114 + // Try to get color type via capabilities
  115 + const nlohmann::json& gamuttype = utils::safeGetMember(lightState, "capabilities", "control", "colorgamuttype");
  116 + if (gamuttype.is_string())
  117 + {
  118 + const std::string gamut = gamuttype.get<std::string>();
  119 + if (gamut == "A")
  120 + {
  121 + return hasCt ? ColorType::GAMUT_A_TEMPERATURE : ColorType::GAMUT_A;
  122 + }
  123 + else if (gamut == "B")
  124 + {
  125 + return hasCt ? ColorType::GAMUT_B_TEMPERATURE : ColorType::GAMUT_B;
  126 + }
  127 + else if (gamut == "C")
  128 + {
  129 + return hasCt ? ColorType::GAMUT_C_TEMPERATURE : ColorType::GAMUT_C;
  130 + }
  131 + else
  132 + {
  133 + // Only other type is "Other" which does not have an enum value
  134 + return ColorType::UNDEFINED;
  135 + }
  136 + }
  137 + else
  138 + {
  139 + // Old version without capabilities, fall back to hardcoded types
  140 + std::string modelid = lightState.at("modelid").get<std::string>();
  141 + if (getGamutATypes().count(modelid))
  142 + {
  143 + return hasCt ? ColorType::GAMUT_A_TEMPERATURE : ColorType::GAMUT_A;
  144 + }
  145 + else if (getGamutBTypes().count(modelid))
  146 + {
  147 + return hasCt ? ColorType::GAMUT_B_TEMPERATURE : ColorType::GAMUT_B;
  148 + }
  149 + else if (getGamutCTypes().count(modelid))
  150 + {
  151 + return hasCt ? ColorType::GAMUT_C_TEMPERATURE : ColorType::GAMUT_C;
  152 + }
  153 + std::cerr << "Could not determine HueLight color type:" << modelid << "!\n";
  154 + throw HueException(CURRENT_FILE_INFO, "Could not determine HueLight color type!");
  155 + }
  156 +}
131 } // namespace hueplusplus 157 } // namespace hueplusplus
test/test_Hue.cpp
@@ -298,6 +298,7 @@ TEST(Hue, getLight) @@ -298,6 +298,7 @@ TEST(Hue, getLight)
298 EXPECT_EQ(test_light_1.getColorType(), ColorType::TEMPERATURE); 298 EXPECT_EQ(test_light_1.getColorType(), ColorType::TEMPERATURE);
299 299
300 // more coverage stuff 300 // more coverage stuff
  301 + hue_bridge_state["lights"]["1"]["type"] = "Color light";
301 hue_bridge_state["lights"]["1"]["modelid"] = "LCT001"; 302 hue_bridge_state["lights"]["1"]["modelid"] = "LCT001";
302 EXPECT_CALL( 303 EXPECT_CALL(
303 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort())) 304 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
@@ -349,7 +350,7 @@ TEST(Hue, getLight) @@ -349,7 +350,7 @@ TEST(Hue, getLight)
349 EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); 350 EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1");
350 EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_A); 351 EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_A);
351 352
352 - hue_bridge_state["lights"]["1"]["modelid"] = "LWB004"; 353 + hue_bridge_state["lights"]["1"]["type"] = "Dimmable light";
353 EXPECT_CALL( 354 EXPECT_CALL(
354 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort())) 355 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
355 .Times(1) 356 .Times(1)
@@ -366,7 +367,7 @@ TEST(Hue, getLight) @@ -366,7 +367,7 @@ TEST(Hue, getLight)
366 EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); 367 EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1");
367 EXPECT_EQ(test_light_1.getColorType(), ColorType::NONE); 368 EXPECT_EQ(test_light_1.getColorType(), ColorType::NONE);
368 369
369 - hue_bridge_state["lights"]["1"]["modelid"] = "Plug 01"; 370 + hue_bridge_state["lights"]["1"]["type"] = "On/Off light";
370 EXPECT_CALL( 371 EXPECT_CALL(
371 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort())) 372 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
372 .Times(1) 373 .Times(1)
@@ -383,7 +384,7 @@ TEST(Hue, getLight) @@ -383,7 +384,7 @@ TEST(Hue, getLight)
383 EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); 384 EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1");
384 EXPECT_EQ(test_light_1.getColorType(), ColorType::NONE); 385 EXPECT_EQ(test_light_1.getColorType(), ColorType::NONE);
385 386
386 - hue_bridge_state["lights"]["1"]["modelid"] = "ABC000"; 387 + hue_bridge_state["lights"]["1"]["type"] = "unknown light type";
387 EXPECT_CALL( 388 EXPECT_CALL(
388 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort())) 389 *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
389 .Times(1) 390 .Times(1)
test/test_HueLight.cpp
@@ -103,7 +103,7 @@ protected: @@ -103,7 +103,7 @@ protected:
103 hue_bridge_state["lights"]["3"]["swupdate"] = nlohmann::json::object(); 103 hue_bridge_state["lights"]["3"]["swupdate"] = nlohmann::json::object();
104 hue_bridge_state["lights"]["3"]["swupdate"]["state"] = "noupdates"; 104 hue_bridge_state["lights"]["3"]["swupdate"]["state"] = "noupdates";
105 hue_bridge_state["lights"]["3"]["swupdate"]["lastinstall"] = nullptr; 105 hue_bridge_state["lights"]["3"]["swupdate"]["lastinstall"] = nullptr;
106 - hue_bridge_state["lights"]["3"]["type"] = "Color extended light"; 106 + hue_bridge_state["lights"]["3"]["type"] = "Extended color light";
107 hue_bridge_state["lights"]["3"]["name"] = "Hue lamp 3"; 107 hue_bridge_state["lights"]["3"]["name"] = "Hue lamp 3";
108 hue_bridge_state["lights"]["3"]["modelid"] = "LCT010"; 108 hue_bridge_state["lights"]["3"]["modelid"] = "LCT010";
109 hue_bridge_state["lights"]["3"]["manufacturername"] = "Philips"; 109 hue_bridge_state["lights"]["3"]["manufacturername"] = "Philips";
@@ -236,10 +236,10 @@ TEST_F(HueLightTest, getType) @@ -236,10 +236,10 @@ TEST_F(HueLightTest, getType)
236 236
237 EXPECT_EQ("Dimmable light", ctest_light_1.getType()); 237 EXPECT_EQ("Dimmable light", ctest_light_1.getType());
238 EXPECT_EQ("Color light", ctest_light_2.getType()); 238 EXPECT_EQ("Color light", ctest_light_2.getType());
239 - EXPECT_EQ("Color extended light", ctest_light_3.getType()); 239 + EXPECT_EQ("Extended color light", ctest_light_3.getType());
240 EXPECT_EQ("Dimmable light", test_light_1.getType()); 240 EXPECT_EQ("Dimmable light", test_light_1.getType());
241 EXPECT_EQ("Color light", test_light_2.getType()); 241 EXPECT_EQ("Color light", test_light_2.getType());
242 - EXPECT_EQ("Color extended light", test_light_3.getType()); 242 + EXPECT_EQ("Extended color light", test_light_3.getType());
243 } 243 }
244 244
245 TEST_F(HueLightTest, getName) 245 TEST_F(HueLightTest, getName)
@@ -406,10 +406,10 @@ TEST_F(HueLightTest, getColorType) @@ -406,10 +406,10 @@ TEST_F(HueLightTest, getColorType)
406 406
407 EXPECT_EQ(ColorType::NONE, ctest_light_1.getColorType()); 407 EXPECT_EQ(ColorType::NONE, ctest_light_1.getColorType());
408 EXPECT_EQ(ColorType::GAMUT_A, ctest_light_2.getColorType()); 408 EXPECT_EQ(ColorType::GAMUT_A, ctest_light_2.getColorType());
409 - EXPECT_EQ(ColorType::GAMUT_C, ctest_light_3.getColorType()); 409 + EXPECT_EQ(ColorType::GAMUT_C_TEMPERATURE, ctest_light_3.getColorType());
410 EXPECT_EQ(ColorType::NONE, test_light_1.getColorType()); 410 EXPECT_EQ(ColorType::NONE, test_light_1.getColorType());
411 EXPECT_EQ(ColorType::GAMUT_A, test_light_2.getColorType()); 411 EXPECT_EQ(ColorType::GAMUT_A, test_light_2.getColorType());
412 - EXPECT_EQ(ColorType::GAMUT_C, test_light_3.getColorType()); 412 + EXPECT_EQ(ColorType::GAMUT_C_TEMPERATURE, test_light_3.getColorType());
413 } 413 }
414 414
415 TEST_F(HueLightTest, KelvinToMired) 415 TEST_F(HueLightTest, KelvinToMired)