Commit a8eb8aa7228cbac17d1c91cc90e4160bb30bc2dc

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent 8cf83417

Add Rule class.

include/hueplusplus/Rule.h 0 → 100644
  1 +/**
  2 + \file Rule.h
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#ifndef INCLUDE_HUEPLUSPLUS_RULE_H
  23 +#define INCLUDE_HUEPLUSPLUS_RULE_H
  24 +
  25 +#include <string>
  26 +
  27 +#include "APICache.h"
  28 +#include "HueCommandAPI.h"
  29 +#include "Schedule.h"
  30 +#include "TimePattern.h"
  31 +
  32 +namespace hueplusplus
  33 +{
  34 +
  35 +class Condition
  36 +{
  37 +public:
  38 + //! \brief Specifies which operation is used to check the condition
  39 + enum class Operator
  40 + {
  41 + eq, //!< Attribute is equal to specified value (for bool and int)
  42 + gt, //!< Attribute is greater than specified value (for int)
  43 + lt, //!< Attribute is less than specified value (for int)
  44 + dx, //!< Attribute has changed (no value given)
  45 + ddx, //!< Delayed attribute has changed (no value given)
  46 + stable, //!< Stable for a given time
  47 + not_stable, //!< Not stable for a given time
  48 + in, //!< Time is in the given interval (triggered on start time)
  49 + not_in //!< Time is not in the interval (triggered on end time)
  50 + };
  51 +
  52 +public:
  53 + Condition(const std::string& address, Operator op, const std::string& value);
  54 +
  55 + std::string getAddress() const;
  56 + Operator getOperator() const;
  57 + std::string getValue() const;
  58 +
  59 + nlohmann::json toJson() const;
  60 +
  61 + static Condition parse(const nlohmann::json& json);
  62 +private:
  63 + std::string address;
  64 + Operator op;
  65 + std::string value;
  66 +};
  67 +
  68 +class Rule
  69 +{
  70 +public:
  71 + //! \brief Creates rule with id
  72 + //! \param id Rule id in the bridge
  73 + //! \param commands HueCommandAPI for requests
  74 + //! \param refreshDuration Time between refreshing the cached state.
  75 + Rule(int id, const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration);
  76 +
  77 + //! \brief Refreshes internal cached state.
  78 + //! \param force \c true forces a refresh, regardless of how long the last refresh was ago.
  79 + //! \c false to only refresh when enough time has passed (needed e.g. when calling only const methods).
  80 + //! \throws std::system_error when system or socket operations fail
  81 + //! \throws HueException when response contained no body
  82 + //! \throws HueAPIResponseException when response contains an error
  83 + //! \throws nlohmann::json::parse_error when response could not be parsed
  84 + void refresh(bool force = false);
  85 +
  86 + //! \brief Get rule identifier
  87 + int getId() const;
  88 +
  89 + //! \brief Get rule name
  90 + std::string getName() const;
  91 +
  92 + //! \brief Get created time
  93 + time::AbsoluteTime getCreated() const;
  94 +
  95 + //! \brief Get time the rule was last triggered
  96 + time::AbsoluteTime getLastTriggered() const;
  97 +
  98 + //! \brief Get the number of times the rule was triggered
  99 + int getTimesTriggered() const;
  100 +
  101 + //! \brief Get whether rule is enabled or disabled
  102 + bool isEnabled() const;
  103 +
  104 + //! \brief Get user that created or last changed the rule.
  105 + std::string getOwner() const;
  106 +
  107 + std::vector<Condition> getConditions() const;
  108 + std::vector<ScheduleCommand> getActions() const;
  109 +private:
  110 + int id;
  111 + APICache state;
  112 +};
  113 +
  114 +} // namespace hueplusplus
  115 +
  116 +#endif
include/hueplusplus/Schedule.h
@@ -31,6 +31,8 @@ namespace hueplusplus @@ -31,6 +31,8 @@ namespace hueplusplus
31 //! 31 //!
32 //! The command makes either a POST, PUT or DELETE request with a given body 32 //! The command makes either a POST, PUT or DELETE request with a given body
33 //! to an address on the bridge. 33 //! to an address on the bridge.
  34 +//!
  35 +//! A ScheduleCommand can also be created by StateTransaction::toScheduleCommand().
34 class ScheduleCommand 36 class ScheduleCommand
35 { 37 {
36 public: 38 public:
@@ -74,14 +76,6 @@ private: @@ -74,14 +76,6 @@ private:
74 class Schedule 76 class Schedule
75 { 77 {
76 public: 78 public:
77 - //! \brief Enabled status of the Schedule  
78 - enum class Status  
79 - {  
80 - disabled, //!< Schedule is disabled  
81 - enabled //!< Schedule is enabled  
82 - };  
83 -  
84 -public:  
85 //! \brief Construct Schedule that exists in the bridge 79 //! \brief Construct Schedule that exists in the bridge
86 //! \param id Schedule ID 80 //! \param id Schedule ID
87 //! \param commands HueCommandAPI for requests 81 //! \param commands HueCommandAPI for requests
@@ -109,8 +103,8 @@ public: @@ -109,8 +103,8 @@ public:
109 //! \brief Get time when the event(s) will occur 103 //! \brief Get time when the event(s) will occur
110 //! \returns TimePattern in local timezone 104 //! \returns TimePattern in local timezone
111 time::TimePattern getTime() const; 105 time::TimePattern getTime() const;
112 - //! \brief Get schedule enabled/disabled status  
113 - Status getStatus() const; 106 + //! \brief Get whether schedule is enabled or disabled
  107 + bool isEnabled() const;
114 //! \brief Get autodelete 108 //! \brief Get autodelete
115 //! 109 //!
116 //! When autodelete is set to true, the schedule is removed after it expires. 110 //! When autodelete is set to true, the schedule is removed after it expires.
@@ -161,7 +155,7 @@ public: @@ -161,7 +155,7 @@ public:
161 //! \throws HueException when response contained no body 155 //! \throws HueException when response contained no body
162 //! \throws HueAPIResponseException when response contains an error 156 //! \throws HueAPIResponseException when response contains an error
163 //! \throws nlohmann::json::parse_error when response could not be parsed 157 //! \throws nlohmann::json::parse_error when response could not be parsed
164 - void setStatus(Status status); 158 + void setEnabled(bool enabled);
165 //! \brief Set autodelete 159 //! \brief Set autodelete
166 //! \param autodelete Whether to delete the schedule after it expires 160 //! \param autodelete Whether to delete the schedule after it expires
167 //! \throws std::system_error when system or socket operations fail 161 //! \throws std::system_error when system or socket operations fail
@@ -202,8 +196,8 @@ public: @@ -202,8 +196,8 @@ public:
202 //! \see Schedule::setTime 196 //! \see Schedule::setTime
203 CreateSchedule& setTime(const time::TimePattern& time); 197 CreateSchedule& setTime(const time::TimePattern& time);
204 //! \brief Set status 198 //! \brief Set status
205 - //! \see Schedule::setStatus  
206 - CreateSchedule& setStatus(Schedule::Status status); 199 + //! \see Schedule::setEnabled
  200 + CreateSchedule& setStatus(bool enabled);
207 //! \brief Set autodelete 201 //! \brief Set autodelete
208 //! \see Schedule::setAutodelete 202 //! \see Schedule::setAutodelete
209 CreateSchedule& setAutodelete(bool autodelete); 203 CreateSchedule& setAutodelete(bool autodelete);
@@ -213,7 +207,7 @@ public: @@ -213,7 +207,7 @@ public:
213 CreateSchedule& setRecycle(bool recycle); 207 CreateSchedule& setRecycle(bool recycle);
214 208
215 //! \brief Get request to create the schedule. 209 //! \brief Get request to create the schedule.
216 -//! \returns JSON request for a POST to create the new schedule 210 + //! \returns JSON request for a POST to create the new schedule
217 nlohmann::json getRequest() const; 211 nlohmann::json getRequest() const;
218 212
219 private: 213 private:
src/Rule.cpp 0 → 100644
  1 +/**
  2 + \file Rule.cpp
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Jan Rogall - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#include <hueplusplus/Rule.h>
  23 +
  24 +namespace hueplusplus
  25 +{
  26 +Condition::Condition(const std::string& address, Operator op, const std::string& value)
  27 + : address(address), op(op), value(value)
  28 +{ }
  29 +std::string Condition::getAddress() const
  30 +{
  31 + return address;
  32 +}
  33 +Condition::Operator Condition::getOperator() const
  34 +{
  35 + return op;
  36 +}
  37 +std::string Condition::getValue() const
  38 +{
  39 + return value;
  40 +}
  41 +
  42 +nlohmann::json Condition::toJson() const
  43 +{
  44 + std::string opStr;
  45 + switch (op)
  46 + {
  47 + case Operator::eq:
  48 + opStr = "eq";
  49 + break;
  50 + case Operator::gt:
  51 + opStr = "gt";
  52 + break;
  53 + case Operator::lt:
  54 + opStr = "lt";
  55 + break;
  56 + case Operator::dx:
  57 + opStr = "dx";
  58 + break;
  59 + case Operator::ddx:
  60 + opStr = "ddx";
  61 + break;
  62 + case Operator::stable:
  63 + opStr = "stable";
  64 + break;
  65 + case Operator::not_stable:
  66 + opStr = "eq";
  67 + break;
  68 + case Operator::in:
  69 + opStr = "eq";
  70 + break;
  71 + case Operator::not_in:
  72 + opStr = "eq";
  73 + break;
  74 + }
  75 +
  76 + nlohmann::json result = {{"address", address}, {"operator", opStr}};
  77 + if (!value.empty())
  78 + {
  79 + result["value"] = value;
  80 + }
  81 + return result;
  82 +}
  83 +
  84 +Condition Condition::parse(const nlohmann::json& json)
  85 +{
  86 + std::string address = json.at("address").get<std::string>();
  87 + std::string value = json.value("value", "");
  88 + std::string opStr = json.at("operator").get<std::string>();
  89 + Operator op = Operator::eq;
  90 + if (opStr == "gt")
  91 + {
  92 + op = Operator::gt;
  93 + }
  94 + else if (opStr == "lt")
  95 + {
  96 + op = Operator::lt;
  97 + }
  98 + else if (opStr == "dx")
  99 + {
  100 + op = Operator::dx;
  101 + }
  102 + else if (opStr == "ddx")
  103 + {
  104 + op = Operator::ddx;
  105 + }
  106 + else if (opStr == "stable")
  107 + {
  108 + op = Operator::stable;
  109 + }
  110 + else if (opStr == "not_stable")
  111 + {
  112 + op = Operator::not_stable;
  113 + }
  114 + else if (opStr == "in")
  115 + {
  116 + op = Operator::in;
  117 + }
  118 + else if (opStr == "not_in")
  119 + {
  120 + op = Operator::not_in;
  121 + }
  122 +
  123 + return Condition(address, op, value);
  124 +}
  125 +
  126 +Rule::Rule(int id, const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration)
  127 + : id(id), state("/rules/" + id, commands, refreshDuration)
  128 +{ }
  129 +
  130 +void Rule::refresh(bool force)
  131 +{
  132 + if (force)
  133 + {
  134 + state.refresh();
  135 + }
  136 + else
  137 + {
  138 + state.getValue();
  139 + }
  140 +}
  141 +
  142 +int Rule::getId() const
  143 +{
  144 + return id;
  145 +}
  146 +
  147 +std::string Rule::getName() const
  148 +{
  149 + return state.getValue().at("name").get<std::string>();
  150 +}
  151 +
  152 +time::AbsoluteTime Rule::getCreated() const
  153 +{
  154 + return time::AbsoluteTime::parseUTC(state.getValue().at("creationtime").get<std::string>());
  155 +}
  156 +
  157 +time::AbsoluteTime Rule::getLastTriggered() const
  158 +{
  159 + return time::AbsoluteTime::parseUTC(state.getValue().at("lasttriggered").get<std::string>());
  160 +}
  161 +
  162 +int Rule::getTimesTriggered() const
  163 +{
  164 + return state.getValue().at("timestriggered").get<int>();
  165 +}
  166 +
  167 +bool Rule::isEnabled() const
  168 +{
  169 + return state.getValue().at("status").get<std::string>() == "enabled";
  170 +}
  171 +
  172 +std::string Rule::getOwner() const
  173 +{
  174 + return state.getValue().at("owner").get<std::string>();
  175 +}
  176 +
  177 +std::vector<Condition> Rule::getConditions() const
  178 +{
  179 + std::vector<Condition> result;
  180 + const nlohmann::json& conditions = state.getValue().at("conditions");
  181 + for (const nlohmann::json& c : conditions)
  182 + {
  183 + result.emplace_back(Condition::parse(c));
  184 + }
  185 + return result;
  186 +}
  187 +
  188 +std::vector<ScheduleCommand> Rule::getActions() const
  189 +{
  190 + std::vector<ScheduleCommand> result;
  191 + const nlohmann::json& actions = state.getValue().at("actions");
  192 + for (const nlohmann::json& a : actions)
  193 + {
  194 + result.emplace_back(a);
  195 + }
  196 + return result;
  197 +}
  198 +
  199 +} // namespace hueplusplus
0 \ No newline at end of file 200 \ No newline at end of file
src/Schedule.cpp
@@ -118,13 +118,13 @@ time::TimePattern Schedule::getTime() const @@ -118,13 +118,13 @@ time::TimePattern Schedule::getTime() const
118 // return time::TimePattern::parse(state.getValue().at("time").get<std::string>()); 118 // return time::TimePattern::parse(state.getValue().at("time").get<std::string>());
119 } 119 }
120 120
121 -Schedule::Status Schedule::getStatus() const 121 +bool Schedule::isEnabled() const
122 { 122 {
123 if (state.getValue().at("status").get<std::string>() == "enabled") 123 if (state.getValue().at("status").get<std::string>() == "enabled")
124 { 124 {
125 - return Status::enabled; 125 + return true;
126 } 126 }
127 - return Status::disabled; 127 + return false;
128 } 128 }
129 129
130 bool Schedule::getAutodelete() const 130 bool Schedule::getAutodelete() const
@@ -174,9 +174,9 @@ void Schedule::setTime(const time::TimePattern&amp; timePattern) @@ -174,9 +174,9 @@ void Schedule::setTime(const time::TimePattern&amp; timePattern)
174 refresh(); 174 refresh();
175 } 175 }
176 176
177 -void Schedule::setStatus(Status status) 177 +void Schedule::setEnabled(bool enabled)
178 { 178 {
179 - sendPutRequest({{"status", status == Status::enabled ? "enabled" : "disabled"}}, CURRENT_FILE_INFO); 179 + sendPutRequest({{"status", enabled ? "enabled" : "disabled"}}, CURRENT_FILE_INFO);
180 refresh(); 180 refresh();
181 } 181 }
182 182
@@ -215,9 +215,9 @@ CreateSchedule&amp; CreateSchedule::setTime(const time::TimePattern&amp; time) @@ -215,9 +215,9 @@ CreateSchedule&amp; CreateSchedule::setTime(const time::TimePattern&amp; time)
215 return *this; 215 return *this;
216 } 216 }
217 217
218 -CreateSchedule& CreateSchedule::setStatus(Schedule::Status status) 218 +CreateSchedule& CreateSchedule::setStatus(bool enabled)
219 { 219 {
220 - request["status"] = (status == Schedule::Status::enabled) ? "enabled" : "disabled"; 220 + request["status"] = enabled ? "enabled" : "disabled";
221 return *this; 221 return *this;
222 } 222 }
223 223
test/test_Schedule.cpp
@@ -149,13 +149,13 @@ TEST_F(ScheduleTest, getStatus) @@ -149,13 +149,13 @@ TEST_F(ScheduleTest, getStatus)
149 scheduleState["status"] = "enabled"; 149 scheduleState["status"] = "enabled";
150 expectGetState(id); 150 expectGetState(id);
151 const Schedule schedule(id, commands, std::chrono::seconds(0)); 151 const Schedule schedule(id, commands, std::chrono::seconds(0));
152 - EXPECT_EQ(Schedule::Status::enabled, schedule.getStatus()); 152 + EXPECT_EQ(true, schedule.isEnabled());
153 } 153 }
154 { 154 {
155 scheduleState["status"] = "disabled"; 155 scheduleState["status"] = "disabled";
156 expectGetState(id); 156 expectGetState(id);
157 const Schedule schedule(id, commands, std::chrono::seconds(0)); 157 const Schedule schedule(id, commands, std::chrono::seconds(0));
158 - EXPECT_EQ(Schedule::Status::disabled, schedule.getStatus()); 158 + EXPECT_EQ(false, schedule.isEnabled());
159 } 159 }
160 } 160 }
161 161
@@ -261,7 +261,7 @@ TEST_F(ScheduleTest, setStatus) @@ -261,7 +261,7 @@ TEST_F(ScheduleTest, setStatus)
261 *handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort())) 261 *handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort()))
262 .WillOnce(Return(response)); 262 .WillOnce(Return(response));
263 expectGetState(id); 263 expectGetState(id);
264 - schedule.setStatus(Schedule::Status::enabled); 264 + schedule.setEnabled(true);
265 } 265 }
266 { 266 {
267 nlohmann::json request = {{"status", "disabled"}}; 267 nlohmann::json request = {{"status", "disabled"}};
@@ -270,7 +270,7 @@ TEST_F(ScheduleTest, setStatus) @@ -270,7 +270,7 @@ TEST_F(ScheduleTest, setStatus)
270 *handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort())) 270 *handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort()))
271 .WillOnce(Return(response)); 271 .WillOnce(Return(response));
272 expectGetState(id); 272 expectGetState(id);
273 - schedule.setStatus(Schedule::Status::disabled); 273 + schedule.setEnabled(false);
274 } 274 }
275 } 275 }
276 276
@@ -329,11 +329,11 @@ TEST(CreateSchedule, setStatus) @@ -329,11 +329,11 @@ TEST(CreateSchedule, setStatus)
329 { 329 {
330 { 330 {
331 const nlohmann::json request = {{"status", "enabled"}}; 331 const nlohmann::json request = {{"status", "enabled"}};
332 - EXPECT_EQ(request, CreateSchedule().setStatus(Schedule::Status::enabled).getRequest()); 332 + EXPECT_EQ(request, CreateSchedule().setStatus(true).getRequest());
333 } 333 }
334 { 334 {
335 const nlohmann::json request = {{"status", "disabled"}}; 335 const nlohmann::json request = {{"status", "disabled"}};
336 - EXPECT_EQ(request, CreateSchedule().setStatus(Schedule::Status::disabled).getRequest()); 336 + EXPECT_EQ(request, CreateSchedule().setStatus(false).getRequest());
337 } 337 }
338 } 338 }
339 339