diff --git a/include/hueplusplus/Units.h b/include/hueplusplus/ColorUnits.h index abf7133..c263b62 100644 --- a/include/hueplusplus/Units.h +++ b/include/hueplusplus/ColorUnits.h @@ -1,5 +1,5 @@ /** - \file Units.h + \file ColorUnits.h Copyright Notice\n Copyright (C) 2017 Jan Rogall - developer\n Copyright (C) 2017 Moritz Wirger - developer\n @@ -55,6 +55,14 @@ struct ColorGamut XY corrected(const XY& xy) const; }; +namespace gamut +{ +constexpr ColorGamut gamutA {{0.704f, 0.296f}, {0.2151f, 0.7106f}, {0.138f, 0.08f}}; +constexpr ColorGamut gamutB {{0.675f, 0.322f}, {0.409f, 0.518f}, {0.167f, 0.04f}}; +constexpr ColorGamut gamutC {{0.692f, 0.308f}, {0.17f, 0.7f}, {0.153f, 0.048f}}; +constexpr ColorGamut maxGamut {{1.f, 0.f}, {0.f, 1.f}, {0.f, 0.f}}; +} // namespace gamut + struct RGB { uint8_t r; diff --git a/include/hueplusplus/HueLight.h b/include/hueplusplus/HueLight.h index 432adf6..5e25b45 100644 --- a/include/hueplusplus/HueLight.h +++ b/include/hueplusplus/HueLight.h @@ -195,6 +195,14 @@ public: //! \return String containing the software version virtual std::string getSwVersion() const; + + //! \brief Const function that returns the color type of the light. + //! + //! \return ColorType containig the color type of the light + virtual ColorType getColorType() const; + + ColorGamut getColorGamut() const; + ///@} //! \name Light state ///@{ @@ -234,11 +242,6 @@ public: //! \return Bool that is true, when the light is on and false, when off virtual bool isOn() const; - //! \brief Const function that returns the color type of the light. - //! - //! \return ColorType containig the color type of the light - virtual ColorType getColorType() const; - //! \brief Const function to check whether this light has brightness control //! //! \return Bool that is true when the light has specified abilities and false diff --git a/include/hueplusplus/Scene.h b/include/hueplusplus/Scene.h index 7c0de25..cb0ae79 100644 --- a/include/hueplusplus/Scene.h +++ b/include/hueplusplus/Scene.h @@ -30,7 +30,7 @@ #include "APICache.h" #include "TimePattern.h" -#include "Units.h" +#include "ColorUnits.h" namespace hueplusplus { @@ -49,7 +49,7 @@ public: HueSaturation getHueSat() const; bool hasXY() const; - XY getXY() const; + XYBrightness getXY() const; bool hasCt() const; int getCt() const; diff --git a/include/hueplusplus/StateTransaction.h b/include/hueplusplus/StateTransaction.h index 1030cb8..2861062 100644 --- a/include/hueplusplus/StateTransaction.h +++ b/include/hueplusplus/StateTransaction.h @@ -25,6 +25,7 @@ #include +#include "ColorUnits.h" #include "HueCommandAPI.h" #include "Schedule.h" @@ -99,6 +100,8 @@ public: //! \note If this transaction is for a light, the light needs to have rgb color control. //! \note Will also turn on the light if nothing else is specified StateTransaction&& setColorXY(float x, float y) &&; + + StateTransaction&& setColorXY(const XYBrightness& xy) &&; //! \brief Set light color temperature. //! \param mired Color temperature in mired from 153 to 500 //! \returns This transaction for chaining calls diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63b7ac5..c3f2cb8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,7 +16,7 @@ set(hueplusplus_SOURCES SimpleColorTemperatureStrategy.cpp StateTransaction.cpp TimePattern.cpp - Units.cpp + "ColorUnits.cpp" UPnP.cpp Utils.cpp ) diff --git a/src/Units.cpp b/src/ColorUnits.cpp index 967749c..9f62600 100644 --- a/src/Units.cpp +++ b/src/ColorUnits.cpp @@ -1,6 +1,27 @@ +/** + \file ColorUnits.cpp + Copyright Notice\n + Copyright (C) 2020 Jan Rogall - developer\n + + This file is part of hueplusplus. + + hueplusplus is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hueplusplus is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with hueplusplus. If not, see . +**/ + #include -#include +#include namespace hueplusplus { @@ -129,8 +150,8 @@ RGB RGB::fromXY(const XYBrightness& xy) const float gammaG = g <= 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * pow(g, (1.0f / 2.4f)) - 0.055f; const float gammaB = b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * pow(b, (1.0f / 2.4f)) - 0.055f; - return RGB {static_cast(std::round(gammaR * 255.f)), static_cast(std::round(gammaG * 255.f)), - static_cast(std::round(gammaB * 255.f))}; + return RGB {static_cast(std::round(gammaR * 255.f)), static_cast(std::round(gammaG * 255.f)), + static_cast(std::round(gammaB * 255.f))}; } RGB RGB::fromXY(const XYBrightness& xy, const ColorGamut& gamut) diff --git a/src/HueLight.cpp b/src/HueLight.cpp index 0959646..151589e 100644 --- a/src/HueLight.cpp +++ b/src/HueLight.cpp @@ -124,6 +124,35 @@ ColorType HueLight::getColorType() const return colorType; } +ColorGamut HueLight::getColorGamut() const +{ + switch (colorType) + { + case ColorType::GAMUT_A: + case ColorType::GAMUT_A_TEMPERATURE: + return gamut::gamutA; + case ColorType::GAMUT_B: + case ColorType::GAMUT_B_TEMPERATURE: + return gamut::gamutB; + case ColorType::GAMUT_C: + case ColorType::GAMUT_C_TEMPERATURE: + return gamut::gamutC; + default: { + const nlohmann::json& capabilitiesGamut + = utils::safeGetMember(state.getValue(), "capabilities", "control", "colorgamut"); + if (capabilitiesGamut.is_array() && capabilitiesGamut.size() == 3) + { + // Other gamut + return ColorGamut {{capabilitiesGamut[0].at(0), capabilitiesGamut[0].at(1)}, + {capabilitiesGamut[1].at(0), capabilitiesGamut[1].at(1)}, + {capabilitiesGamut[2].at(0), capabilitiesGamut[2].at(1)}}; + } + // Unknown or no color light + return gamut::maxGamut; + } + } +} + unsigned int HueLight::KelvinToMired(unsigned int kelvin) const { return int(0.5f + (1000000 / kelvin)); @@ -141,7 +170,8 @@ bool HueLight::alert() StateTransaction HueLight::transaction() { - return StateTransaction(state.getCommandAPI(), "/lights/" + std::to_string(id) + "/state", state.getValue().at("state")); + return StateTransaction( + state.getCommandAPI(), "/lights/" + std::to_string(id) + "/state", state.getValue().at("state")); } void HueLight::refresh() diff --git a/src/Scene.cpp b/src/Scene.cpp index a6d596e..8ed70a6 100644 --- a/src/Scene.cpp +++ b/src/Scene.cpp @@ -56,10 +56,10 @@ bool LightState::hasXY() const return state.count("xy"); } -XY LightState::getXY() const +XYBrightness LightState::getXY() const { const nlohmann::json& xy = state.at("xy"); - return XY {xy[0].get(), xy[1].get()}; + return XYBrightness {{xy[0].get(), xy[1].get()}, state.at("bri").get() / 255.f}; } bool LightState::hasCt() const diff --git a/src/StateTransaction.cpp b/src/StateTransaction.cpp index 8661098..b1ee2db 100644 --- a/src/StateTransaction.cpp +++ b/src/StateTransaction.cpp @@ -108,6 +108,14 @@ StateTransaction&& StateTransaction::setColorXY(float x, float y) && return std::move(*this); } +StateTransaction&& StateTransaction::setColorXY(const XYBrightness& xy)&& +{ + request["xy"] = { xy.xy.x, xy.xy.y }; + request["bri"] = static_cast(std::round(xy.brightness * 255.f)); + + return std::move(*this); +} + StateTransaction&& StateTransaction::setColorTemperature(unsigned int mired) && { unsigned int clamped = std::max(153u, std::min(mired, 500u)); diff --git a/test/test_Scene.cpp b/test/test_Scene.cpp index d0ec9cc..3be19c9 100644 --- a/test/test_Scene.cpp +++ b/test/test_Scene.cpp @@ -66,11 +66,12 @@ TEST(LightState, XY) EXPECT_FALSE(LightState(nlohmann::json::object()).hasXY()); const float x = 0.6f; const float y = 0.3f; - nlohmann::json json {{"xy", {x, y}}}; + nlohmann::json json {{"xy", {x, y}}, {"bri", 255}}; const LightState state {json}; EXPECT_TRUE(state.hasXY()); - EXPECT_FLOAT_EQ(x, state.getXY().x); - EXPECT_FLOAT_EQ(y, state.getXY().y); + EXPECT_FLOAT_EQ(x, state.getXY().xy.x); + EXPECT_FLOAT_EQ(y, state.getXY().xy.y); + EXPECT_FLOAT_EQ(1.f, state.getXY().brightness); } TEST(LightState, Ct) @@ -286,12 +287,12 @@ TEST_F(SceneTest, getVersion) TEST_F(SceneTest, getLightstates) { - const std::string id = "125asav3"; + const std::string id = "125asav3"; { - const std::map lightstates{ + const std::map lightstates { {3, LightStateBuilder().setOn(false).setBrightness(100).setXY({0.3, 0.2}).create()}, {4, LightStateBuilder().setOn(false).setBrightness(200).setXY({0.3, 0.2}).setColorloop(true).create()}, - {5, LightStateBuilder().setOn(true).setBrightness(100).setXY({0.3, 0.2}).create()} }; + {5, LightStateBuilder().setOn(true).setBrightness(100).setXY({0.3, 0.2}).create()}}; nlohmann::json lightstatesJson; for (const auto& entry : lightstates) {