Commit 8bfb374147baa3244aa40045dc2d7a46c0ec1275
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.
Showing
6 changed files
with
79 additions
and
44 deletions
include/hueplusplus/HueDeviceTypes.h
| ... | ... | @@ -33,12 +33,16 @@ namespace hueplusplus |
| 33 | 33 | class HueLightFactory |
| 34 | 34 | { |
| 35 | 35 | public: |
| 36 | - HueLightFactory(const HueCommandAPI& commands); | |
| 36 | + HueLightFactory(const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration); | |
| 37 | 37 | |
| 38 | 38 | HueLight createLight(const nlohmann::json& lightState, int id); |
| 39 | 39 | |
| 40 | 40 | private: |
| 41 | + ColorType getColorType(const nlohmann::json& lightState, bool hasCt) const; | |
| 42 | + | |
| 43 | +private: | |
| 41 | 44 | HueCommandAPI commands; |
| 45 | + std::chrono::steady_clock::duration refreshDuration; | |
| 42 | 46 | std::shared_ptr<BrightnessStrategy> simpleBrightness; |
| 43 | 47 | std::shared_ptr<ColorTemperatureStrategy> simpleColorTemperature; |
| 44 | 48 | std::shared_ptr<ColorTemperatureStrategy> extendedColorTemperature; | ... | ... |
include/hueplusplus/HueLight.h
| ... | ... | @@ -118,7 +118,13 @@ public: |
| 118 | 118 | |
| 119 | 119 | //! \brief Const function that returns the light type |
| 120 | 120 | //! |
| 121 | + //! The type determines which functions the light has. | |
| 121 | 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 | 128 | virtual std::string getType() const; |
| 123 | 129 | |
| 124 | 130 | //! \brief Function that returns the name of the light. | ... | ... |
src/Hue.cpp
| ... | ... | @@ -137,7 +137,7 @@ Hue::Hue(const std::string& ip, const int port, const std::string& username, |
| 137 | 137 | http_handler(std::move(handler)), |
| 138 | 138 | commands(ip, port, username, http_handler), |
| 139 | 139 | stateCache("", commands, refreshDuration), |
| 140 | - lightFactory(commands) | |
| 140 | + lightFactory(commands, refreshDuration) | |
| 141 | 141 | {} |
| 142 | 142 | |
| 143 | 143 | std::string Hue::getBridgeIP() |
| ... | ... | @@ -179,9 +179,7 @@ std::string Hue::requestUsername() |
| 179 | 179 | // [{"success":{"username": "<username>"}}] |
| 180 | 180 | username = jsonUser.get<std::string>(); |
| 181 | 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 | 183 | std::cout << "Success! Link button was pressed!\n"; |
| 186 | 184 | std::cout << "Username is \"" << username << "\"\n"; |
| 187 | 185 | break; |
| ... | ... | @@ -523,6 +521,6 @@ void Hue::setHttpHandler(std::shared_ptr<const IHttpHandler> handler) |
| 523 | 521 | http_handler = handler; |
| 524 | 522 | commands = HueCommandAPI(ip, port, username, handler); |
| 525 | 523 | stateCache = APICache("", commands, stateCache.getRefreshDuration()); |
| 526 | - lightFactory = HueLightFactory(commands); | |
| 524 | + lightFactory = HueLightFactory(commands, stateCache.getRefreshDuration()); | |
| 527 | 525 | } |
| 528 | 526 | } // namespace hueplusplus | ... | ... |
src/HueDeviceTypes.cpp
| ... | ... | @@ -31,6 +31,7 @@ |
| 31 | 31 | #include "hueplusplus/SimpleBrightnessStrategy.h" |
| 32 | 32 | #include "hueplusplus/SimpleColorHueStrategy.h" |
| 33 | 33 | #include "hueplusplus/SimpleColorTemperatureStrategy.h" |
| 34 | +#include "hueplusplus/Utils.h" | |
| 34 | 35 | |
| 35 | 36 | namespace hueplusplus |
| 36 | 37 | { |
| ... | ... | @@ -56,32 +57,11 @@ const std::set<std::string>& getGamutATypes() |
| 56 | 57 | = {"LST001", "LLC005", "LLC006", "LLC007", "LLC010", "LLC011", "LLC012", "LLC013", "LLC014"}; |
| 57 | 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 | 60 | } // namespace |
| 82 | 61 | |
| 83 | -HueLightFactory::HueLightFactory(const HueCommandAPI& commands) | |
| 62 | +HueLightFactory::HueLightFactory(const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration) | |
| 84 | 63 | : commands(commands), |
| 64 | + refreshDuration(refreshDuration), | |
| 85 | 65 | simpleBrightness(std::make_shared<SimpleBrightnessStrategy>()), |
| 86 | 66 | simpleColorHue(std::make_shared<SimpleColorHueStrategy>()), |
| 87 | 67 | extendedColorHue(std::make_shared<ExtendedColorHueStrategy>()), |
| ... | ... | @@ -97,35 +77,81 @@ HueLight HueLightFactory::createLight(const nlohmann::json& lightState, int id) |
| 97 | 77 | |
| 98 | 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 | 81 | light.colorType = ColorType::NONE; |
| 102 | 82 | return light; |
| 103 | 83 | } |
| 104 | 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 | 87 | light.colorType = ColorType::NONE; |
| 108 | 88 | return light; |
| 109 | 89 | } |
| 110 | 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 | 93 | light.colorType = ColorType::TEMPERATURE; |
| 114 | 94 | return light; |
| 115 | 95 | } |
| 116 | 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 | 100 | return light; |
| 121 | 101 | } |
| 122 | 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 | 106 | return light; |
| 127 | 107 | } |
| 128 | 108 | std::cerr << "Could not determine HueLight type:" << type << "!\n"; |
| 129 | 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 | 157 | } // namespace hueplusplus | ... | ... |
test/test_Hue.cpp
| ... | ... | @@ -298,6 +298,7 @@ TEST(Hue, getLight) |
| 298 | 298 | EXPECT_EQ(test_light_1.getColorType(), ColorType::TEMPERATURE); |
| 299 | 299 | |
| 300 | 300 | // more coverage stuff |
| 301 | + hue_bridge_state["lights"]["1"]["type"] = "Color light"; | |
| 301 | 302 | hue_bridge_state["lights"]["1"]["modelid"] = "LCT001"; |
| 302 | 303 | EXPECT_CALL( |
| 303 | 304 | *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort())) |
| ... | ... | @@ -349,7 +350,7 @@ TEST(Hue, getLight) |
| 349 | 350 | EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); |
| 350 | 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 | 354 | EXPECT_CALL( |
| 354 | 355 | *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort())) |
| 355 | 356 | .Times(1) |
| ... | ... | @@ -366,7 +367,7 @@ TEST(Hue, getLight) |
| 366 | 367 | EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); |
| 367 | 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 | 371 | EXPECT_CALL( |
| 371 | 372 | *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort())) |
| 372 | 373 | .Times(1) |
| ... | ... | @@ -383,7 +384,7 @@ TEST(Hue, getLight) |
| 383 | 384 | EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1"); |
| 384 | 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 | 388 | EXPECT_CALL( |
| 388 | 389 | *handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort())) |
| 389 | 390 | .Times(1) | ... | ... |
test/test_HueLight.cpp
| ... | ... | @@ -103,7 +103,7 @@ protected: |
| 103 | 103 | hue_bridge_state["lights"]["3"]["swupdate"] = nlohmann::json::object(); |
| 104 | 104 | hue_bridge_state["lights"]["3"]["swupdate"]["state"] = "noupdates"; |
| 105 | 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 | 107 | hue_bridge_state["lights"]["3"]["name"] = "Hue lamp 3"; |
| 108 | 108 | hue_bridge_state["lights"]["3"]["modelid"] = "LCT010"; |
| 109 | 109 | hue_bridge_state["lights"]["3"]["manufacturername"] = "Philips"; |
| ... | ... | @@ -236,10 +236,10 @@ TEST_F(HueLightTest, getType) |
| 236 | 236 | |
| 237 | 237 | EXPECT_EQ("Dimmable light", ctest_light_1.getType()); |
| 238 | 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 | 240 | EXPECT_EQ("Dimmable light", test_light_1.getType()); |
| 241 | 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 | 245 | TEST_F(HueLightTest, getName) |
| ... | ... | @@ -406,10 +406,10 @@ TEST_F(HueLightTest, getColorType) |
| 406 | 406 | |
| 407 | 407 | EXPECT_EQ(ColorType::NONE, ctest_light_1.getColorType()); |
| 408 | 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 | 410 | EXPECT_EQ(ColorType::NONE, test_light_1.getColorType()); |
| 411 | 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 | 415 | TEST_F(HueLightTest, KelvinToMired) | ... | ... |