Commit a90a97795ecf77b2bc314d63ad72b8800bb3fb8c

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent a90248d3

Add documentation for Sensor and SensorList.

Add definitions for constexpr strings.
include/hueplusplus/Sensor.h
... ... @@ -33,17 +33,28 @@
33 33  
34 34 namespace hueplusplus
35 35 {
  36 +//! \brief Specifies light alert modes
36 37 enum class Alert
37 38 {
38   - none,
39   - select,
40   - lselect
  39 + none, //!< No alert
  40 + select, //!< Select alert (breathe cycle)
  41 + lselect //!< Long select alert (15s breathe)
41 42 };
  43 +
  44 +//! \brief Convert alert to string form
  45 +//! \param alert Enum value
  46 +//! \returns "none", "select" or "lselect"
42 47 std::string alertToString(Alert alert);
  48 +
  49 +//! \brief Convert string to Alert enum
  50 +//! \param s String representation
  51 +//! \returns Alert::select or Alert::lselect when \c s matches, otherwise Alert::none
43 52 Alert alertFromString(const std::string& s);
  53 +
  54 +//! \brief Class for generic or unknown sensor types
44 55 //!
45   -//! Generic class for Hue sensors
46   -//!
  56 +//! It is recommended to instead use the classes for specific types in \ref sensors.
  57 +//! This class should only be used if the type cannot be known or is not supported.
47 58 class Sensor : public BaseDevice
48 59 {
49 60 public:
... ... @@ -56,51 +67,134 @@ public:
56 67 //!\name Config attributes
57 68 ///@{
58 69  
  70 + //! \brief Get whether sensor has an on attribute
59 71 bool hasOn() const;
60   - // Check whether sensor is on. Does not update when off
  72 + //! \brief Get whether sensor is turned on
  73 + //!
  74 + //! Sensors which are off do not change their status
  75 + //! \throws nlohmann::json::out_of_range when on attribute does not exist.
61 76 bool isOn() const;
  77 + //! \brief Turn sensor on or off
  78 + //! \throws std::system_error when system or socket operations fail
  79 + //! \throws HueException when response contained no body
  80 + //! \throws HueAPIResponseException when response contains an error
  81 + //! \throws nlohmann::json::parse_error when response could not be parsed
62 82 void setOn(bool on);
63 83  
  84 + //! \brief Get whether sensor has a battery state
64 85 bool hasBatteryState() const;
65   - // Battery state in percent
  86 + //! \brief Get battery state
  87 + //! \returns Battery state in percent
  88 + //! \throws nlohmann::json::out_of_range when sensor has no battery status.
66 89 int getBatteryState() const;
  90 + //! \brief Set battery state
  91 + //! \throws std::system_error when system or socket operations fail
  92 + //! \throws HueException when response contained no body
  93 + //! \throws HueAPIResponseException when response contains an error
  94 + //! \throws nlohmann::json::parse_error when response could not be parsed
67 95 void setBatteryState(int percent);
68 96  
  97 + //! \brief Get whether sensor has alerts
69 98 bool hasAlert() const;
  99 + //! \brief Get last sent alert
  100 + //! \throws nlohmann::json::out_of_range when sensor has no alert.
70 101 Alert getLastAlert() const;
  102 + //! \brief Send alert
  103 + //! \throws std::system_error when system or socket operations fail
  104 + //! \throws HueException when response contained no body
  105 + //! \throws HueAPIResponseException when response contains an error
  106 + //! \throws nlohmann::json::parse_error when response could not be parsed
71 107 void sendAlert(Alert type);
72 108  
  109 + //! \brief Get whether sensor has reachable validation
73 110 bool hasReachable() const;
  111 + //! \brief Get whether sensor is reachable
  112 + //! \throws nlohmann::json::out_of_range when sensor has no reachable validation
74 113 bool isReachable() const;
75 114  
  115 + //! \brief Get whether sensor has user test mode
76 116 bool hasUserTest() const;
  117 + //! \brief Enable or disable user test mode
  118 + //!
  119 + //! In user test mode, changes are reported more frequently.#
  120 + //! It remains on for 120 seconds or until turned off.
  121 + //! \throws std::system_error when system or socket operations fail
  122 + //! \throws HueException when response contained no body
  123 + //! \throws HueAPIResponseException when response contains an error
  124 + //! \throws nlohmann::json::parse_error when response could not be parsed
77 125 void setUserTest(bool enabled);
78 126  
  127 + //! \brief Get whether sensor has a URL
79 128 bool hasURL() const;
  129 + //! \brief Get sensor URL
  130 + //!
  131 + //! Only CLIP sensors can have a URL.
80 132 std::string getURL() const;
  133 + //! \brief Set sensor URL
  134 + //! \throws std::system_error when system or socket operations fail
  135 + //! \throws HueException when response contained no body
  136 + //! \throws HueAPIResponseException when response contains an error
  137 + //! \throws nlohmann::json::parse_error when response could not be parsed
81 138 void setURL(const std::string& url);
82   -
  139 +
  140 + //! \brief Get pending config entries, if they exist
  141 + //! \returns The keys of config entries which have been modified,
  142 + //! but were not committed to the device.
  143 + //!
  144 + //! Attempts to set pending config entries may cause errors.
83 145 std::vector<std::string> getPendingConfig() const;
84   -
  146 +
  147 + //! \brief Get whether the sensor has a LED indicator
85 148 bool hasLEDIndication() const;
  149 + //! \brief Get whether the indicator LED is on
  150 + //! \throws nlohmann::json::out_of_range when sensor has no LED
86 151 bool getLEDIndication() const;
  152 + //! \brief Turn LED indicator on or off
  153 + //! \throws std::system_error when system or socket operations fail
  154 + //! \throws HueException when response contained no body
  155 + //! \throws HueAPIResponseException when response contains an error
  156 + //! \throws nlohmann::json::parse_error when response could not be parsed
87 157 void setLEDIndication(bool on);
88 158  
  159 + //! \brief Get entire config object
  160 + //! \returns A json object with the sensor configuration.
89 161 nlohmann::json getConfig() const;
  162 + //! \brief Set attribute in the sensor config
  163 + //! \param key Key of the config attribute
  164 + //! \param value Any value to set the attribute to
  165 + //!
  166 + //! Can be used to configure sensors with additional config entries.
90 167 void setConfigAttribute(const std::string& key, const nlohmann::json& value);
91 168  
92 169 ///@}
93   -
  170 +
  171 + //! \brief Get time of last status update
  172 + //! \returns The last update time, or a time with a zero duration from epoch
  173 + //! if the last update time is not set.
94 174 time::AbsoluteTime getLastUpdated() const;
95   -
  175 +
  176 + //! \brief Get state object
96 177 nlohmann::json getState() const;
  178 + //! \brief Set part of the sensor state
  179 + //! \param key Key in the state object
  180 + //! \param value New value
  181 + //!
  182 + //! The state can usually only be set on CLIP sensors, not on physical devices.
97 183 void setStateAttribute(const std::string& key, const nlohmann::json& value);
98 184  
  185 + //! \brief Check if sensor is Hue certified
99 186 bool isCertified() const;
  187 + //! \brief Check if sensor is primary sensor of the device
  188 + //!
  189 + //! When there are multiple sensors on one physical device (same MAC address),
  190 + //! the primary device is used for the device information.
100 191 bool isPrimary() const;
101 192  
  193 + //! \brief Convert sensor to a specific type
  194 + //! \tparam T Sensor type to convert to (from \ref sensors)
  195 + //! \throws HueException when sensor type does not match requested type
102 196 template <typename T>
103   - T asSensorType() const &
  197 + T asSensorType() const&
104 198 {
105 199 if (getType() != T::typeStr)
106 200 {
... ... @@ -108,6 +202,11 @@ public:
108 202 }
109 203 return T(*this);
110 204 }
  205 + //! \brief Convert sensor to a specific type
  206 + //! \tparam T Sensor type to convert to (from \ref sensors)
  207 + //! \throws HueException when sensor type does not match requested type
  208 + //!
  209 + //! Move construct \c T to be more efficient when the type is wanted directly.
111 210 template <typename T>
112 211 T asSensorType() &&
113 212 {
... ... @@ -119,46 +218,124 @@ public:
119 218 }
120 219 };
121 220  
  221 +//! \brief Parameters for creating a new Sensor
  222 +//!
  223 +//! Can be used like a builder object with chained calls.
122 224 class CreateSensor
123 225 {
124 226 public:
  227 + //! \brief Construct with necessary parameters
  228 + //! \param name Human readable name
  229 + //! \param modelid Model id of the sensor
  230 + //! \param swversion Software version, may be empty
  231 + //! \param type Sensor type name (see types in \ref sensors)
  232 + //! \param uniqueid Globally unique ID
  233 + //! (MAC address of the device, extended with a unique endpoint id)
  234 + //! \param manufacturername Name of the device manufacturer
125 235 CreateSensor(const std::string& name, const std::string& modelid, const std::string& swversion,
126 236 const std::string& type, const std::string& uniqueid, const std::string& manufacturername);
127 237  
  238 + //! \brief Set state object
  239 + //! \param state Sensor state, contents depend on the type.
  240 + //! \returns this object for chaining calls
128 241 CreateSensor& setState(const nlohmann::json& state);
  242 + //! \brief Set config object
  243 + //! \param config Sensor config, configs depend on the type. See getters in Sensor for examples.
  244 + //! \returns this object for chaining calls
129 245 CreateSensor& setConfig(const nlohmann::json& config);
  246 + //! \brief Enable recycling, delete automatically when not referenced
  247 + //! \returns this object for chaining calls
130 248 CreateSensor& setRecycle(bool recycle);
131 249  
  250 + //! \brief Get request to create the sensor
  251 + //! \returns JSON request for a POST to create the new sensor
132 252 nlohmann::json getRequest() const;
  253 +
133 254 protected:
134 255 nlohmann::json request;
135 256 };
136 257  
  258 +//! \brief Classes for specific sensor types
  259 +//!
  260 +//! Classes should have a typeStr member with the type name.
137 261 namespace sensors
138 262 {
  263 +//! \brief Daylight sensor to detect sunrise and sunset
  264 +//!
  265 +//! Every bridge has a daylight sensor always available.
139 266 class DaylightSensor : public BaseDevice
140 267 {
141 268 public:
  269 + //! \brief Construct from generic sensor
142 270 explicit DaylightSensor(Sensor sensor) : BaseDevice(std::move(sensor)) { }
143 271  
  272 + //! \brief Check if sensor is on
  273 + //!
  274 + //! Sensors which are off do not change their status
144 275 bool isOn() const;
  276 +
  277 + //! \brief Enable or disable sensor
  278 + //! \throws std::system_error when system or socket operations fail
  279 + //! \throws HueException when response contained no body
  280 + //! \throws HueAPIResponseException when response contains an error
  281 + //! \throws nlohmann::json::parse_error when response could not be parsed
145 282 void setOn(bool on);
146 283  
  284 + //! \brief Get whether sensor has a battery state
147 285 bool hasBatteryState() const;
  286 + //! \brief Get battery state
  287 + //! \returns Battery state in percent
  288 + //! \throws nlohmann::json::out_of_range when sensor has no battery status.
148 289 int getBatteryState() const;
  290 + //! \brief Set battery state
  291 + //! \throws std::system_error when system or socket operations fail
  292 + //! \throws HueException when response contained no body
  293 + //! \throws HueAPIResponseException when response contains an error
  294 + //! \throws nlohmann::json::parse_error when response could not be parsed
149 295 void setBatteryState(int percent);
150 296  
  297 + //! \brief Set GPS coordinates for the calculation
  298 + //! \param latitude Decimal latitude coordinate "DDD.DDDD{N|S}" with leading zeros ending with N or S.
  299 + //! "none" to reset. (Empty string is null, which may be used instead of none in the future)
  300 + //! \param longitude Longitude coordinate (same format as latitude), ending with W or E
  301 + //! \throws std::system_error when system or socket operations fail
  302 + //! \throws HueException when response contained no body
  303 + //! \throws HueAPIResponseException when response contains an error
  304 + //! \throws nlohmann::json::parse_error when response could not be parsed
151 305 void setCoordinates(const std::string& latitude, const std::string& longitude);
  306 + //! \brief Check whether coordinates are configured
  307 + //!
  308 + //! There is no way to retrieve the configured coordinates.
152 309 bool isConfigured() const;
153 310  
  311 + //! \brief Get time offset in minutes to sunrise
  312 + //!
  313 + //! The daylight is true if it is \c offset minutes after sunrise.
154 314 int getSunriseOffset() const;
  315 + //! \brief Set sunrise offset time
  316 + //! \param minutes Minutes from -120 to 120
  317 + //! \throws std::system_error when system or socket operations fail
  318 + //! \throws HueException when response contained no body
  319 + //! \throws HueAPIResponseException when response contains an error
  320 + //! \throws nlohmann::json::parse_error when response could not be parsed
155 321 void setSunriseOffset(int minutes);
156 322  
  323 + //! \brief Get time offset in minutes to sunset
  324 + //!
  325 + //! The daylight is false if it is \c offset minutes after sunset.
157 326 int getSunsetOffset() const;
  327 + //! \brief Set sunset offset time
  328 + //! \param minutes Minutes from -120 to 120
  329 + //! \throws std::system_error when system or socket operations fail
  330 + //! \throws HueException when response contained no body
  331 + //! \throws HueAPIResponseException when response contains an error
  332 + //! \throws nlohmann::json::parse_error when response could not be parsed
158 333 void setSunsetOffset(int minutes);
159 334  
  335 + //! \brief Get reported daylight status
160 336 bool isDaylight() const;
161 337  
  338 + //! \brief Daylight sensor type name
162 339 static constexpr const char* typeStr = "Daylight";
163 340 };
164 341  
... ...
include/hueplusplus/SensorList.h
... ... @@ -27,16 +27,34 @@
27 27  
28 28 namespace hueplusplus
29 29 {
  30 +//! \brief Handles a list of Sensor%s with type specific getters
  31 +//!
  32 +//! Allows to directly get the requested sensor type or all sensors of a given type.
30 33 class SensorList : public CreateableResourceList<Sensor, int, CreateSensor>
31 34 {
32 35 public:
33 36 using CreateableResourceList::CreateableResourceList;
34 37  
  38 + //! \brief Get sensor specified by id, convert to \c T
  39 + //! \param id Sensor id
  40 + //! \tparam T Sensor type to convert to (from \ref sensors)
  41 + //! \returns The sensor matching the id and type
  42 + //! \throws HueException when id does not exist or type does not match
  43 + //! \throws std::system_error when system or socket operations fail
  44 + //! \throws HueAPIResponseException when response contains an error
  45 + //! \throws nlohmann::json::parse_error when response could not be parsed
35 46 template <typename T>
36 47 T getAsType(int id)
37 48 {
38 49 return get(id).asSensorType<T>();
39 50 }
  51 + //! \brief Get all sensors of type \c T
  52 + //! \tparam T Sensor type to get (from \ref sensors)
  53 + //! \returns All sensors matching the type
  54 + //! \throws HueException when response contains no body
  55 + //! \throws std::system_error when system or socket operations fail
  56 + //! \throws HueAPIResponseException when response contains an error
  57 + //! \throws nlohmann::json::parse_error when response could not be parsed
40 58 template <typename T>
41 59 std::vector<T> getAllByType()
42 60 {
... ... @@ -54,7 +72,9 @@ public:
54 72 }
55 73  
56 74 protected:
  75 + //! \brief Protected defaulted move constructor
57 76 SensorList(SensorList&&) = default;
  77 + //! \brief Protected defaulted move assignment
58 78 SensorList& operator=(SensorList&&) = default;
59 79 };
60 80 } // namespace hueplusplus
... ...
src/CLIPSensors.cpp
... ... @@ -63,57 +63,65 @@ std::string BaseCLIP::getURL() const
63 63 }
64 64 void BaseCLIP::setURL(const std::string& url)
65 65 {
66   - sendPutRequest("/config", nlohmann::json{ {"url", url} }, CURRENT_FILE_INFO);
  66 + sendPutRequest("/config", nlohmann::json {{"url", url}}, CURRENT_FILE_INFO);
67 67 }
68 68  
69   -
70 69 time::AbsoluteTime BaseCLIP::getLastUpdated() const
71 70 {
72 71 const nlohmann::json& stateJson = state.getValue().at("state");
73 72 auto it = stateJson.find("lastupdated");
74 73 if (it == stateJson.end() || !it->is_string() || *it == "none")
75 74 {
76   - return time::AbsoluteTime(std::chrono::system_clock::time_point(std::chrono::seconds{ 0 }));
  75 + return time::AbsoluteTime(std::chrono::system_clock::time_point(std::chrono::seconds {0}));
77 76 }
78 77 return time::AbsoluteTime::parseUTC(it->get<std::string>());
79 78 }
80 79  
  80 +constexpr const char* CLIPSwitch::typeStr;
  81 +
81 82 int CLIPSwitch::getButtonEvent() const
82 83 {
83 84 return state.getValue().at("state").at("buttonevent").get<int>();
84 85 }
85 86 void CLIPSwitch::setButtonEvent(int code)
86 87 {
87   - sendPutRequest("/state", nlohmann::json{ {"buttonevent", code} }, CURRENT_FILE_INFO);
  88 + sendPutRequest("/state", nlohmann::json {{"buttonevent", code}}, CURRENT_FILE_INFO);
88 89 }
89 90  
  91 +constexpr const char* CLIPOpenClose::typeStr;
  92 +
90 93 bool CLIPOpenClose::isOpen() const
91 94 {
92 95 return state.getValue().at("state").at("open").get<bool>();
93 96 }
94 97 void CLIPOpenClose::setOpen(bool open)
95 98 {
96   - sendPutRequest("/state", nlohmann::json{ {"open", open} }, CURRENT_FILE_INFO);
  99 + sendPutRequest("/state", nlohmann::json {{"open", open}}, CURRENT_FILE_INFO);
97 100 }
98 101  
  102 +constexpr const char* CLIPPresence::typeStr;
  103 +
99 104 bool CLIPPresence::getPresence() const
100 105 {
101 106 return state.getValue().at("state").at("presence").get<bool>();
102 107 }
103 108 void CLIPPresence::setPresence(bool presence)
104 109 {
105   - sendPutRequest("/state", nlohmann::json{ {"presence", presence} }, CURRENT_FILE_INFO);
  110 + sendPutRequest("/state", nlohmann::json {{"presence", presence}}, CURRENT_FILE_INFO);
106 111 }
107 112  
  113 +constexpr const char* CLIPTemperature::typeStr;
  114 +
108 115 int CLIPTemperature::getTemperature() const
109 116 {
110 117 return state.getValue().at("state").at("temperature").get<int>();
111 118 }
112 119 void CLIPTemperature::setTemperature(int temperature)
113 120 {
114   - sendPutRequest("/state", nlohmann::json{ {"temperature", temperature} }, CURRENT_FILE_INFO);
  121 + sendPutRequest("/state", nlohmann::json {{"temperature", temperature}}, CURRENT_FILE_INFO);
115 122 }
116 123  
  124 +constexpr const char* CLIPHumidity::typeStr;
117 125  
118 126 int CLIPHumidity::getHumidity() const
119 127 {
... ... @@ -121,9 +129,11 @@ int CLIPHumidity::getHumidity() const
121 129 }
122 130 void CLIPHumidity::setHumidity(int humidity)
123 131 {
124   - sendPutRequest("/state", nlohmann::json{ {"humidity", humidity} }, CURRENT_FILE_INFO);
  132 + sendPutRequest("/state", nlohmann::json {{"humidity", humidity}}, CURRENT_FILE_INFO);
125 133 }
126 134  
  135 +constexpr const char* CLIPLightLevel::typeStr;
  136 +
127 137 int CLIPLightLevel::getDarkThreshold() const
128 138 {
129 139 return state.getValue().at("config").at("tholddark").get<int>();
... ... @@ -131,7 +141,7 @@ int CLIPLightLevel::getDarkThreshold() const
131 141  
132 142 void CLIPLightLevel::setDarkThreshold(int threshold)
133 143 {
134   - sendPutRequest("/config", nlohmann::json{ { "tholddark", threshold} }, CURRENT_FILE_INFO);
  144 + sendPutRequest("/config", nlohmann::json {{"tholddark", threshold}}, CURRENT_FILE_INFO);
135 145 }
136 146 int CLIPLightLevel::getThresholdOffset() const
137 147 {
... ... @@ -140,7 +150,7 @@ int CLIPLightLevel::getThresholdOffset() const
140 150  
141 151 void CLIPLightLevel::setThresholdOffset(int offset)
142 152 {
143   - sendPutRequest("/config", nlohmann::json{ { "tholdoffset", offset} }, CURRENT_FILE_INFO);
  153 + sendPutRequest("/config", nlohmann::json {{"tholdoffset", offset}}, CURRENT_FILE_INFO);
144 154 }
145 155  
146 156 int CLIPLightLevel::getLightLevel() const
... ... @@ -150,7 +160,7 @@ int CLIPLightLevel::getLightLevel() const
150 160  
151 161 void CLIPLightLevel::setLightLevel(int level)
152 162 {
153   - sendPutRequest("/state", nlohmann::json{ {"lightlevel", level} }, CURRENT_FILE_INFO);
  163 + sendPutRequest("/state", nlohmann::json {{"lightlevel", level}}, CURRENT_FILE_INFO);
154 164 }
155 165  
156 166 bool CLIPLightLevel::isDark() const
... ... @@ -163,15 +173,19 @@ bool CLIPLightLevel::isDaylight() const
163 173 return state.getValue().at("state").at("daylight").get<bool>();
164 174 }
165 175  
  176 +constexpr const char* CLIPGenericFlag::typeStr;
  177 +
166 178 bool CLIPGenericFlag::getFlag() const
167 179 {
168 180 return state.getValue().at("state").at("flag").get<bool>();
169 181 }
170 182 void CLIPGenericFlag::setFlag(bool flag)
171 183 {
172   - sendPutRequest("/state", nlohmann::json{ {"flag", flag} }, CURRENT_FILE_INFO);
  184 + sendPutRequest("/state", nlohmann::json {{"flag", flag}}, CURRENT_FILE_INFO);
173 185 }
174 186  
  187 +constexpr const char* CLIPGenericStatus::typeStr;
  188 +
175 189 int CLIPGenericStatus::getStatus() const
176 190 {
177 191 return state.getValue().at("config").at("status").get<int>();
... ... @@ -179,7 +193,7 @@ int CLIPGenericStatus::getStatus() const
179 193  
180 194 void CLIPGenericStatus::setStatus(int status)
181 195 {
182   - sendPutRequest("/config", nlohmann::json{ { "status", status} }, CURRENT_FILE_INFO);
  196 + sendPutRequest("/config", nlohmann::json {{"status", status}}, CURRENT_FILE_INFO);
183 197 }
184 198 } // namespace sensors
185 199 } // namespace hueplusplus
186 200 \ No newline at end of file
... ...
src/Sensor.cpp
... ... @@ -261,6 +261,8 @@ nlohmann::json CreateSensor::getRequest() const
261 261 namespace sensors
262 262 {
263 263  
  264 +constexpr const char* DaylightSensor::typeStr;
  265 +
264 266 bool DaylightSensor::isOn() const
265 267 {
266 268 return state.getValue().at("config").at("on").get<bool>();
... ...