Commit 505a0e055d123c38d56a8384db854e593fc1a2fc
Committed by
Moritz Wirger
1 parent
eee2f0ea
Make request trimming on StateTransaction optional.
Values already set in the state can still be outdated, so there is a manual override for keeping them.
Showing
2 changed files
with
68 additions
and
37 deletions
include/hueplusplus/StateTransaction.h
| @@ -52,14 +52,17 @@ public: | @@ -52,14 +52,17 @@ public: | ||
| 52 | StateTransaction(StateTransaction&&) = default; | 52 | StateTransaction(StateTransaction&&) = default; |
| 53 | 53 | ||
| 54 | //! \brief Commit transaction and make request. | 54 | //! \brief Commit transaction and make request. |
| 55 | + //! \param trimRequest Optional. When true, request parameters that are unneccessary based on | ||
| 56 | + //! the current state are removed. This reduces load on the bridge. On the other hand, an outdated | ||
| 57 | + //! state might cause requests to be dropped unexpectedly. Has no effect on groups. | ||
| 55 | //! \returns true on success or when no change was requested. | 58 | //! \returns true on success or when no change was requested. |
| 56 | - //! \note After changing the state of a HueLight or Group, | 59 | + //! \note After changing the state of a HueLight or Group, |
| 57 | //! refresh() must be called if the updated values are needed immediately. | 60 | //! refresh() must be called if the updated values are needed immediately. |
| 58 | //! \throws std::system_error when system or socket operations fail | 61 | //! \throws std::system_error when system or socket operations fail |
| 59 | //! \throws HueException when response contains no body | 62 | //! \throws HueException when response contains no body |
| 60 | //! \throws HueAPIResponseException when response contains an error | 63 | //! \throws HueAPIResponseException when response contains an error |
| 61 | //! \throws nlohmann::json::parse_error when response could not be parsed | 64 | //! \throws nlohmann::json::parse_error when response could not be parsed |
| 62 | - bool commit() &&; | 65 | + bool commit(bool trimRequest = true) &&; |
| 63 | 66 | ||
| 64 | //! \brief Turn light on or off. | 67 | //! \brief Turn light on or off. |
| 65 | //! \param on true for on, false for off | 68 | //! \param on true for on, false for off |
| @@ -132,7 +135,7 @@ public: | @@ -132,7 +135,7 @@ public: | ||
| 132 | //! \brief Set transition time for the request. | 135 | //! \brief Set transition time for the request. |
| 133 | //! \param transition Transition time in 100ms, default for any request is 400ms. | 136 | //! \param transition Transition time in 100ms, default for any request is 400ms. |
| 134 | //! \returns This transaction for chaining calls | 137 | //! \returns This transaction for chaining calls |
| 135 | - //! \note The transition only applies to the current request. | 138 | + //! \note The transition only applies to the current request. |
| 136 | //! A request without any changes only containing a transition is pointless and is not sent. | 139 | //! A request without any changes only containing a transition is pointless and is not sent. |
| 137 | StateTransaction&& setTransition(uint16_t transition) &&; | 140 | StateTransaction&& setTransition(uint16_t transition) &&; |
| 138 | //! \brief Trigger an alert. | 141 | //! \brief Trigger an alert. |
| @@ -147,7 +150,11 @@ public: | @@ -147,7 +150,11 @@ public: | ||
| 147 | //! \returns This transaction for chaining calls | 150 | //! \returns This transaction for chaining calls |
| 148 | StateTransaction&& stopAlert() &&; | 151 | StateTransaction&& stopAlert() &&; |
| 149 | 152 | ||
| 150 | -protected: | 153 | +private: |
| 154 | + //! \brief Remove parts from request that are already set in state | ||
| 155 | + void trimRequest(); | ||
| 156 | + | ||
| 157 | +private: | ||
| 151 | const HueCommandAPI& commands; | 158 | const HueCommandAPI& commands; |
| 152 | std::string path; | 159 | std::string path; |
| 153 | nlohmann::json state; | 160 | nlohmann::json state; |
src/StateTransaction.cpp
| @@ -22,6 +22,8 @@ | @@ -22,6 +22,8 @@ | ||
| 22 | 22 | ||
| 23 | #include "hueplusplus/StateTransaction.h" | 23 | #include "hueplusplus/StateTransaction.h" |
| 24 | 24 | ||
| 25 | +#include <set> | ||
| 26 | + | ||
| 25 | #include "hueplusplus/HueExceptionMacro.h" | 27 | #include "hueplusplus/HueExceptionMacro.h" |
| 26 | #include "hueplusplus/StateTransaction.h" | 28 | #include "hueplusplus/StateTransaction.h" |
| 27 | #include "hueplusplus/Utils.h" | 29 | #include "hueplusplus/Utils.h" |
| @@ -35,8 +37,12 @@ StateTransaction::StateTransaction( | @@ -35,8 +37,12 @@ StateTransaction::StateTransaction( | ||
| 35 | assert(currentState.is_object()); | 37 | assert(currentState.is_object()); |
| 36 | } | 38 | } |
| 37 | 39 | ||
| 38 | -bool StateTransaction::commit() && | 40 | +bool StateTransaction::commit(bool trimRequest) && |
| 39 | { | 41 | { |
| 42 | + if (trimRequest) | ||
| 43 | + { | ||
| 44 | + this->trimRequest(); | ||
| 45 | + } | ||
| 40 | // Empty request or request with only transition makes no sense | 46 | // Empty request or request with only transition makes no sense |
| 41 | if (!request.empty() && !(request.size() == 1 && request.count("transitiontime"))) | 47 | if (!request.empty() && !(request.size() == 1 && request.count("transitiontime"))) |
| 42 | { | 48 | { |
| @@ -49,7 +55,7 @@ bool StateTransaction::commit() && | @@ -49,7 +55,7 @@ bool StateTransaction::commit() && | ||
| 49 | // Turn on if it was turned off | 55 | // Turn on if it was turned off |
| 50 | request["on"] = true; | 56 | request["on"] = true; |
| 51 | } | 57 | } |
| 52 | - else if(request.value("bri", 254) == 0 && state.value("on", true)) | 58 | + else if (request.value("bri", 254) == 0 && state.value("on", true)) |
| 53 | { | 59 | { |
| 54 | // Turn off if brightness is 0 | 60 | // Turn off if brightness is 0 |
| 55 | request["on"] = false; | 61 | request["on"] = false; |
| @@ -64,39 +70,27 @@ bool StateTransaction::commit() && | @@ -64,39 +70,27 @@ bool StateTransaction::commit() && | ||
| 64 | 70 | ||
| 65 | StateTransaction&& StateTransaction::setOn(bool on) && | 71 | StateTransaction&& StateTransaction::setOn(bool on) && |
| 66 | { | 72 | { |
| 67 | - if (!state.count("on") || state["on"] != on) | ||
| 68 | - { | ||
| 69 | - request["on"] = on; | ||
| 70 | - } | 73 | + request["on"] = on; |
| 71 | return std::move(*this); | 74 | return std::move(*this); |
| 72 | } | 75 | } |
| 73 | 76 | ||
| 74 | StateTransaction&& StateTransaction::setBrightness(uint8_t brightness) && | 77 | StateTransaction&& StateTransaction::setBrightness(uint8_t brightness) && |
| 75 | { | 78 | { |
| 76 | uint8_t clamped = std::min<uint8_t>(brightness, 254); | 79 | uint8_t clamped = std::min<uint8_t>(brightness, 254); |
| 77 | - if (!state.count("bri") || state["bri"].get<unsigned int>() != clamped) | ||
| 78 | - { | ||
| 79 | - request["bri"] = clamped; | ||
| 80 | - } | 80 | + request["bri"] = clamped; |
| 81 | return std::move(*this); | 81 | return std::move(*this); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | StateTransaction&& StateTransaction::setColorSaturation(uint8_t saturation) && | 84 | StateTransaction&& StateTransaction::setColorSaturation(uint8_t saturation) && |
| 85 | { | 85 | { |
| 86 | uint8_t clamped = std::min<uint8_t>(saturation, 254); | 86 | uint8_t clamped = std::min<uint8_t>(saturation, 254); |
| 87 | - if (!state.count("sat") || state["sat"].get<unsigned int>() != clamped || state.value("colormode", "") != "hs") | ||
| 88 | - { | ||
| 89 | - request["sat"] = clamped; | ||
| 90 | - } | 87 | + request["sat"] = clamped; |
| 91 | return std::move(*this); | 88 | return std::move(*this); |
| 92 | } | 89 | } |
| 93 | 90 | ||
| 94 | StateTransaction&& StateTransaction::setColorHue(uint16_t hue) && | 91 | StateTransaction&& StateTransaction::setColorHue(uint16_t hue) && |
| 95 | { | 92 | { |
| 96 | - if (!state.count("hue") || state["hue"].get<int>() != hue || state.value("colormode", "") != "hs") | ||
| 97 | - { | ||
| 98 | - request["hue"] = hue; | ||
| 99 | - } | 93 | + request["hue"] = hue; |
| 100 | return std::move(*this); | 94 | return std::move(*this); |
| 101 | } | 95 | } |
| 102 | 96 | ||
| @@ -104,32 +98,20 @@ StateTransaction&& StateTransaction::setColorXY(float x, float y) && | @@ -104,32 +98,20 @@ StateTransaction&& StateTransaction::setColorXY(float x, float y) && | ||
| 104 | { | 98 | { |
| 105 | float clampedX = std::max(0.f, std::min(x, 1.f)); | 99 | float clampedX = std::max(0.f, std::min(x, 1.f)); |
| 106 | float clampedY = std::max(0.f, std::min(y, 1.f)); | 100 | float clampedY = std::max(0.f, std::min(y, 1.f)); |
| 107 | - if (!state.count("xy") || !state.count("colormode") || !state["xy"].is_array() | ||
| 108 | - || !utils::floatEquals(state["xy"][0].get<float>(), clampedX) | ||
| 109 | - || !utils::floatEquals(state["xy"][1].get<float>(), clampedY) || state["colormode"] != "xy") | ||
| 110 | - { | ||
| 111 | - request["xy"] = {clampedX, clampedY}; | ||
| 112 | - } | 101 | + request["xy"] = {clampedX, clampedY}; |
| 113 | return std::move(*this); | 102 | return std::move(*this); |
| 114 | } | 103 | } |
| 115 | 104 | ||
| 116 | StateTransaction&& StateTransaction::setColorTemperature(unsigned int mired) && | 105 | StateTransaction&& StateTransaction::setColorTemperature(unsigned int mired) && |
| 117 | { | 106 | { |
| 118 | unsigned int clamped = std::max(153u, std::min(mired, 500u)); | 107 | unsigned int clamped = std::max(153u, std::min(mired, 500u)); |
| 119 | - if (state.value("ct", 0u) != clamped || state.value("colormode", "") != "ct") | ||
| 120 | - { | ||
| 121 | - request["ct"] = clamped; | ||
| 122 | - } | 108 | + request["ct"] = clamped; |
| 123 | return std::move(*this); | 109 | return std::move(*this); |
| 124 | } | 110 | } |
| 125 | 111 | ||
| 126 | StateTransaction&& StateTransaction::setColorLoop(bool on) && | 112 | StateTransaction&& StateTransaction::setColorLoop(bool on) && |
| 127 | { | 113 | { |
| 128 | - std::string effect = on ? "colorloop" : "none"; | ||
| 129 | - if (state.value("effect", "") != effect) | ||
| 130 | - { | ||
| 131 | - request["effect"] = effect; | ||
| 132 | - } | 114 | + request["effect"] = on ? "colorloop" : "none"; |
| 133 | return std::move(*this); | 115 | return std::move(*this); |
| 134 | } | 116 | } |
| 135 | 117 | ||
| @@ -186,4 +168,46 @@ StateTransaction&& StateTransaction::stopAlert() && | @@ -186,4 +168,46 @@ StateTransaction&& StateTransaction::stopAlert() && | ||
| 186 | request["alert"] = "none"; | 168 | request["alert"] = "none"; |
| 187 | return std::move(*this); | 169 | return std::move(*this); |
| 188 | } | 170 | } |
| 171 | + | ||
| 172 | +void StateTransaction::trimRequest() | ||
| 173 | +{ | ||
| 174 | + static const std::map<std::string, std::string> colormodes | ||
| 175 | + = {{"sat", "hs"}, {"hue", "hs"}, {"xy", "xy"}, {"ct", "ct"}}; | ||
| 176 | + static const std::set<std::string> otherRemove = {"on", "bri", "effect"}; | ||
| 177 | + // Skip when there is no state provided (e.g. for groups) | ||
| 178 | + if (state.empty()) | ||
| 179 | + { | ||
| 180 | + return; | ||
| 181 | + } | ||
| 182 | + for (auto it = request.begin(); it != request.end();) | ||
| 183 | + { | ||
| 184 | + auto colormodeIt = colormodes.find(it.key()); | ||
| 185 | + if (colormodeIt != colormodes.end()) | ||
| 186 | + { | ||
| 187 | + // Only erase color commands if colormode and value matches | ||
| 188 | + auto stateIt = state.find(it.key()); | ||
| 189 | + if (stateIt != state.end() && state.value("colormode", "") == colormodeIt->second) | ||
| 190 | + { | ||
| 191 | + // Compare xy using float comparison | ||
| 192 | + if ((!it->is_array() && *stateIt == *it) | ||
| 193 | + || (stateIt->is_array() && utils::floatEquals((*stateIt)[0].get<float>(), (*it)[0].get<float>()) | ||
| 194 | + && utils::floatEquals((*stateIt)[1].get<float>(), (*it)[1].get<float>()))) | ||
| 195 | + { | ||
| 196 | + it = request.erase(it); | ||
| 197 | + continue; | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + } | ||
| 201 | + else if (otherRemove.count(it.key())) | ||
| 202 | + { | ||
| 203 | + if (state.count(it.key()) && state[it.key()] == *it) | ||
| 204 | + { | ||
| 205 | + it = request.erase(it); | ||
| 206 | + continue; | ||
| 207 | + } | ||
| 208 | + } | ||
| 209 | + ++it; | ||
| 210 | + } | ||
| 211 | +} | ||
| 212 | + | ||
| 189 | } // namespace hueplusplus | 213 | } // namespace hueplusplus |
| 190 | \ No newline at end of file | 214 | \ No newline at end of file |