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 | 52 | StateTransaction(StateTransaction&&) = default; |
| 53 | 53 | |
| 54 | 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 | 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 | 60 | //! refresh() must be called if the updated values are needed immediately. |
| 58 | 61 | //! \throws std::system_error when system or socket operations fail |
| 59 | 62 | //! \throws HueException when response contains no body |
| 60 | 63 | //! \throws HueAPIResponseException when response contains an error |
| 61 | 64 | //! \throws nlohmann::json::parse_error when response could not be parsed |
| 62 | - bool commit() &&; | |
| 65 | + bool commit(bool trimRequest = true) &&; | |
| 63 | 66 | |
| 64 | 67 | //! \brief Turn light on or off. |
| 65 | 68 | //! \param on true for on, false for off |
| ... | ... | @@ -132,7 +135,7 @@ public: |
| 132 | 135 | //! \brief Set transition time for the request. |
| 133 | 136 | //! \param transition Transition time in 100ms, default for any request is 400ms. |
| 134 | 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 | 139 | //! A request without any changes only containing a transition is pointless and is not sent. |
| 137 | 140 | StateTransaction&& setTransition(uint16_t transition) &&; |
| 138 | 141 | //! \brief Trigger an alert. |
| ... | ... | @@ -147,7 +150,11 @@ public: |
| 147 | 150 | //! \returns This transaction for chaining calls |
| 148 | 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 | 158 | const HueCommandAPI& commands; |
| 152 | 159 | std::string path; |
| 153 | 160 | nlohmann::json state; | ... | ... |
src/StateTransaction.cpp
| ... | ... | @@ -22,6 +22,8 @@ |
| 22 | 22 | |
| 23 | 23 | #include "hueplusplus/StateTransaction.h" |
| 24 | 24 | |
| 25 | +#include <set> | |
| 26 | + | |
| 25 | 27 | #include "hueplusplus/HueExceptionMacro.h" |
| 26 | 28 | #include "hueplusplus/StateTransaction.h" |
| 27 | 29 | #include "hueplusplus/Utils.h" |
| ... | ... | @@ -35,8 +37,12 @@ StateTransaction::StateTransaction( |
| 35 | 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 | 46 | // Empty request or request with only transition makes no sense |
| 41 | 47 | if (!request.empty() && !(request.size() == 1 && request.count("transitiontime"))) |
| 42 | 48 | { |
| ... | ... | @@ -49,7 +55,7 @@ bool StateTransaction::commit() && |
| 49 | 55 | // Turn on if it was turned off |
| 50 | 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 | 60 | // Turn off if brightness is 0 |
| 55 | 61 | request["on"] = false; |
| ... | ... | @@ -64,39 +70,27 @@ bool StateTransaction::commit() && |
| 64 | 70 | |
| 65 | 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 | 74 | return std::move(*this); |
| 72 | 75 | } |
| 73 | 76 | |
| 74 | 77 | StateTransaction&& StateTransaction::setBrightness(uint8_t brightness) && |
| 75 | 78 | { |
| 76 | 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 | 81 | return std::move(*this); |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | StateTransaction&& StateTransaction::setColorSaturation(uint8_t saturation) && |
| 85 | 85 | { |
| 86 | 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 | 88 | return std::move(*this); |
| 92 | 89 | } |
| 93 | 90 | |
| 94 | 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 | 94 | return std::move(*this); |
| 101 | 95 | } |
| 102 | 96 | |
| ... | ... | @@ -104,32 +98,20 @@ StateTransaction&& StateTransaction::setColorXY(float x, float y) && |
| 104 | 98 | { |
| 105 | 99 | float clampedX = std::max(0.f, std::min(x, 1.f)); |
| 106 | 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 | 102 | return std::move(*this); |
| 114 | 103 | } |
| 115 | 104 | |
| 116 | 105 | StateTransaction&& StateTransaction::setColorTemperature(unsigned int mired) && |
| 117 | 106 | { |
| 118 | 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 | 109 | return std::move(*this); |
| 124 | 110 | } |
| 125 | 111 | |
| 126 | 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 | 115 | return std::move(*this); |
| 134 | 116 | } |
| 135 | 117 | |
| ... | ... | @@ -186,4 +168,46 @@ StateTransaction&& StateTransaction::stopAlert() && |
| 186 | 168 | request["alert"] = "none"; |
| 187 | 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 | 213 | } // namespace hueplusplus |
| 190 | 214 | \ No newline at end of file | ... | ... |