Commit 3719728f5637054c27831ee9889470afe8c5b987

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

Implement generic sensor.

include/hueplusplus/CLIPSensors.h
@@ -28,20 +28,9 @@ namespace hueplusplus @@ -28,20 +28,9 @@ namespace hueplusplus
28 { 28 {
29 namespace sensors 29 namespace sensors
30 { 30 {
31 -class CLIPSwitch : public BaseDevice 31 +class BaseCLIP : public BaseDevice
32 { 32 {
33 public: 33 public:
34 - CLIPSwitch(Sensor sensor) : BaseDevice(std::move(sensor)) { }  
35 -  
36 - int getButtonEvent() const;  
37 -  
38 - static constexpr const char* typeStr = "CLIPSwitch";  
39 -};  
40 -class CLIPOpenClose : public BaseDevice  
41 -{  
42 -public:  
43 - CLIPOpenClose(Sensor sensor) : BaseDevice(std::move(sensor)) { }  
44 -  
45 bool isOn() const; 34 bool isOn() const;
46 void setOn(bool on); 35 void setOn(bool on);
47 36
@@ -55,100 +44,65 @@ public: @@ -55,100 +44,65 @@ public:
55 std::string getURL() const; 44 std::string getURL() const;
56 void setURL(const std::string& url); 45 void setURL(const std::string& url);
57 46
58 - bool isOpen() const;  
59 -  
60 time::AbsoluteTime getLastUpdated() const; 47 time::AbsoluteTime getLastUpdated() const;
61 -  
62 - static constexpr const char* typeStr = "CLIPOpenClose"; 48 +protected:
  49 + BaseCLIP(Sensor sensor) : BaseDevice(std::move(sensor)) { }
63 }; 50 };
  51 +class CLIPSwitch : public BaseCLIP
  52 +{
  53 +public:
  54 + CLIPSwitch(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
  55 +
  56 + int getButtonEvent() const;
  57 + void setButtonEvent(int code);
64 58
65 -class CLIPPresence : public BaseDevice 59 + static constexpr const char* typeStr = "CLIPSwitch";
  60 +};
  61 +class CLIPOpenClose : public BaseCLIP
66 { 62 {
67 public: 63 public:
68 - bool isOn() const;  
69 - void setOn(bool on); 64 + CLIPOpenClose(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
70 65
71 - bool hasBattery() const;  
72 - int getBatteryState() const;  
73 - void setBatteryState(int percent); 66 + bool isOpen() const;
74 67
75 - bool isReachable() const; 68 + static constexpr const char* typeStr = "CLIPOpenClose";
  69 +};
76 70
77 - bool hasURL() const;  
78 - std::string getURL() const;  
79 - void setURL(const std::string& url); 71 +class CLIPPresence : public BaseCLIP
  72 +{
  73 +public:
  74 + CLIPPresence(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
80 75
81 bool getPresence() const; 76 bool getPresence() const;
82 void setPresence(bool presence); 77 void setPresence(bool presence);
83 78
84 - time::AbsoluteTime getLastUpdated() const;  
85 -  
86 static constexpr const char* typeStr = "CLIPPresence"; 79 static constexpr const char* typeStr = "CLIPPresence";
87 }; 80 };
88 81
89 -class CLIPTemperature : public BaseDevice 82 +class CLIPTemperature : public BaseCLIP
90 { 83 {
91 public: 84 public:
92 - CLIPTemperature(Sensor sensor) : BaseDevice(std::move(sensor)) { }  
93 -  
94 - bool isOn() const;  
95 - void setOn(bool on);  
96 -  
97 - bool hasBattery() const;  
98 - int getBatteryState() const;  
99 - void setBatteryState(int percent);  
100 -  
101 - bool isReachable() const;  
102 -  
103 - bool hasURL() const;  
104 - std::string getURL() const;  
105 - void setURL(const std::string& url); 85 + CLIPTemperature(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
106 86
107 int getTemperature() const; 87 int getTemperature() const;
108 void setTemperature(int temperature); 88 void setTemperature(int temperature);
109 89
110 - time::AbsoluteTime getLastUpdated() const;  
111 -  
112 static constexpr const char* typeStr = "CLIPTemperature"; 90 static constexpr const char* typeStr = "CLIPTemperature";
113 }; 91 };
114 -class CLIPHumidity : public BaseDevice 92 +class CLIPHumidity : public BaseCLIP
115 { 93 {
116 public: 94 public:
117 - CLIPHumidity(Sensor sensor) : BaseDevice(std::move(sensor)) { }  
118 -  
119 - bool isOn() const;  
120 - void setOn(bool on);  
121 -  
122 - bool hasBattery() const;  
123 - int getBatteryState() const;  
124 - void setBatteryState(int percent);  
125 -  
126 - bool isReachable() const;  
127 -  
128 - bool hasURL() const;  
129 - std::string getURL() const;  
130 - void setURL(const std::string& url); 95 + CLIPHumidity(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
131 96
132 int getHumidity() const; 97 int getHumidity() const;
133 void setHumidity(int humidity); 98 void setHumidity(int humidity);
134 99
135 - time::AbsoluteTime getLastUpdated() const;  
136 -  
137 static constexpr const char* typeStr = "CLIPHumidity"; 100 static constexpr const char* typeStr = "CLIPHumidity";
138 }; 101 };
139 -class CLIPLightLevel : public BaseDevice 102 +class CLIPLightLevel : public BaseCLIP
140 { 103 {
141 public: 104 public:
142 - CLIPLightLevel(Sensor sensor) : BaseDevice(std::move(sensor)) { }  
143 -  
144 - bool isOn() const;  
145 - void setOn(bool on);  
146 -  
147 - bool hasBattery() const;  
148 - int getBatteryState() const;  
149 - void setBatteryState(int percent);  
150 -  
151 - bool isReachable() const; 105 + CLIPLightLevel(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
152 106
153 int getDarkThreshold() const; 107 int getDarkThreshold() const;
154 void setDarkThreshold(int threshold); 108 void setDarkThreshold(int threshold);
@@ -156,10 +110,6 @@ public: @@ -156,10 +110,6 @@ public:
156 int getThresholdOffset() const; 110 int getThresholdOffset() const;
157 void setThresholdOffset(int offset); 111 void setThresholdOffset(int offset);
158 112
159 - bool hasURL() const;  
160 - std::string getURL() const;  
161 - void setURL(const std::string& url);  
162 -  
163 void setLightLevel(int level); 113 void setLightLevel(int level);
164 int getLightLevel() const; 114 int getLightLevel() const;
165 bool isDark() const; 115 bool isDark() const;
@@ -167,46 +117,20 @@ public: @@ -167,46 +117,20 @@ public:
167 117
168 static constexpr const char* typeStr = "CLIPLightLevel"; 118 static constexpr const char* typeStr = "CLIPLightLevel";
169 }; 119 };
170 -class CLIPGenericFlag : public BaseDevice 120 +class CLIPGenericFlag : public BaseCLIP
171 { 121 {
172 public: 122 public:
173 - CLIPGenericFlag(Sensor sensor) : BaseDevice(std::move(sensor)) { }  
174 -  
175 - bool isOn() const;  
176 - void setOn(bool on);  
177 -  
178 - bool hasBattery() const;  
179 - int getBatteryState() const;  
180 - void setBatteryState(int percent);  
181 -  
182 - bool isReachable() const;  
183 -  
184 - bool hasURL() const;  
185 - std::string getURL() const;  
186 - void setURL(const std::string& url); 123 + CLIPGenericFlag(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
187 124
188 bool getFlag() const; 125 bool getFlag() const;
189 void setFlag(bool flag); 126 void setFlag(bool flag);
190 127
191 static constexpr const char* typeStr = "CLIPGenericFlag"; 128 static constexpr const char* typeStr = "CLIPGenericFlag";
192 }; 129 };
193 -class CLIPGenericStatus : public BaseDevice 130 +class CLIPGenericStatus : public BaseCLIP
194 { 131 {
195 public: 132 public:
196 - CLIPGenericStatus(Sensor sensor) : BaseDevice(std::move(sensor)) { }  
197 -  
198 - bool isOn() const;  
199 - void setOn(bool on);  
200 -  
201 - bool hasBattery() const;  
202 - int getBatteryState() const;  
203 - void setBatteryState(int percent);  
204 -  
205 - bool isReachable() const;  
206 -  
207 - bool hasURL() const;  
208 - std::string getURL() const;  
209 - void setURL(const std::string& url); 133 + CLIPGenericStatus(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
210 134
211 int getStatus() const; 135 int getStatus() const;
212 void setStatus(int status); 136 void setStatus(int status);
include/hueplusplus/Sensor.h
@@ -32,6 +32,12 @@ @@ -32,6 +32,12 @@
32 32
33 namespace hueplusplus 33 namespace hueplusplus
34 { 34 {
  35 +enum class Alert
  36 +{
  37 + none,
  38 + select,
  39 + lselect
  40 +};
35 //! 41 //!
36 //! Generic class for Hue sensors 42 //! Generic class for Hue sensors
37 //! 43 //!
@@ -51,11 +57,11 @@ public: @@ -51,11 +57,11 @@ public:
51 bool hasBatteryState() const; 57 bool hasBatteryState() const;
52 // Battery state in percent 58 // Battery state in percent
53 int getBatteryState() const; 59 int getBatteryState() const;
54 - bool isReachable() const; 60 + void setBatteryState(int percent);
55 61
56 bool hasAlert() const; 62 bool hasAlert() const;
57 - std::string getLastAlert() const;  
58 - void sendAlert(const std::string& alert); 63 + Alert getLastAlert() const;
  64 + void sendAlert(Alert type);
59 65
60 bool hasReachable() const; 66 bool hasReachable() const;
61 bool isReachable() const; 67 bool isReachable() const;
@@ -76,7 +82,7 @@ public: @@ -76,7 +82,7 @@ public:
76 void setLEDIndication(bool on); 82 void setLEDIndication(bool on);
77 83
78 nlohmann::json getState() const; 84 nlohmann::json getState() const;
79 - time::AbsoluteTime getLastUpdated() const; 85 + void setStateAttribute(const std::string& key, const nlohmann::json& value);
80 86
81 bool isCertified() const; 87 bool isCertified() const;
82 bool isPrimary() const; 88 bool isPrimary() const;
include/hueplusplus/ZLLSensors.h
@@ -28,13 +28,6 @@ namespace hueplusplus @@ -28,13 +28,6 @@ namespace hueplusplus
28 { 28 {
29 namespace sensors 29 namespace sensors
30 { 30 {
31 -enum class Alert  
32 -{  
33 - none,  
34 - select,  
35 - lselect  
36 -};  
37 -  
38 class ZGPSwitch : public BaseDevice 31 class ZGPSwitch : public BaseDevice
39 { 32 {
40 public: 33 public:
src/Sensor.cpp
@@ -21,54 +21,168 @@ @@ -21,54 +21,168 @@
21 21
22 #include "hueplusplus/Sensor.h" 22 #include "hueplusplus/Sensor.h"
23 23
  24 +#include "hueplusplus/HueExceptionMacro.h"
  25 +#include "hueplusplus/Utils.h"
24 #include "json/json.hpp" 26 #include "json/json.hpp"
25 27
26 namespace hueplusplus 28 namespace hueplusplus
27 { 29 {
28 -int Sensor::getButtonEvent() 30 +bool Sensor::hasOn() const
29 { 31 {
30 - if (hasButtonEvent()) 32 + return state.getValue().at("config").count("on") != 0;
  33 +}
  34 +
  35 +bool Sensor::isOn() const
  36 +{
  37 + return state.getValue().at("config").at("on").get<bool>();
  38 +}
  39 +
  40 +void Sensor::setOn(bool on)
  41 +{
  42 + sendPutRequest("/config", {"on", on}, CURRENT_FILE_INFO);
  43 +}
  44 +
  45 +bool Sensor::hasBatteryState() const
  46 +{
  47 + return state.getValue().at("config").count("battery") != 0;
  48 +}
  49 +int Sensor::getBatteryState() const
  50 +{
  51 + return state.getValue().at("config").at("battery").get<int>();
  52 +}
  53 +void Sensor::setBatteryState(int percent)
  54 +{
  55 + sendPutRequest("/config", nlohmann::json {{"battery", percent}}, CURRENT_FILE_INFO);
  56 +}
  57 +bool Sensor::hasAlert() const
  58 +{
  59 + return state.getValue().at("config").count("alert") != 0;
  60 +}
  61 +Alert Sensor::getLastAlert() const
  62 +{
  63 + std::string alert = state.getValue().at("config").at("alert").get<std::string>();
  64 + if (alert == "select")
31 { 65 {
32 - return state.getValue().at("state").at("buttonevent"); 66 + return Alert::select;
  67 + }
  68 + else if (alert == "lselect")
  69 + {
  70 + return Alert::lselect;
  71 + }
  72 + else
  73 + {
  74 + return Alert::none;
33 } 75 }
34 - return 0;  
35 } 76 }
36 -  
37 -int Sensor::getButtonEvent() const 77 +void Sensor::sendAlert(Alert type)
38 { 78 {
39 - if (hasButtonEvent()) 79 + std::string alertStr;
  80 + switch (type)
40 { 81 {
41 - return state.getValue().at("state").at("buttonevent"); 82 + case Alert::lselect:
  83 + alertStr = "lselect";
  84 + break;
  85 + case Alert::select:
  86 + alertStr = "select";
  87 + break;
  88 + default:
  89 + alertStr = "none";
  90 + break;
42 } 91 }
43 - return 0; 92 + sendPutRequest("/state", nlohmann::json {{"alert", alertStr}}, CURRENT_FILE_INFO);
  93 +}
  94 +bool Sensor::hasReachable() const
  95 +{
  96 + return state.getValue().at("config").count("reachable") != 0;
  97 +}
  98 +bool Sensor::isReachable() const
  99 +{
  100 + // If not present, always assume it is reachable (for daylight sensor)
  101 + return state.getValue().at("config").value("reachable", true);
44 } 102 }
45 103
46 -int Sensor::getStatus() 104 +time::AbsoluteTime Sensor::getLastUpdated() const
47 { 105 {
48 - if (hasStatus()) 106 + const nlohmann::json& stateJson = state.getValue().at("state");
  107 + auto it = stateJson.find("lastupdated");
  108 + if (it == stateJson.end() || !it->is_string() || *it == "none")
49 { 109 {
50 - return state.getValue().at("state").at("status"); 110 + return time::AbsoluteTime(std::chrono::system_clock::time_point(std::chrono::seconds {0}));
51 } 111 }
52 - return 0; 112 + return time::AbsoluteTime::parseUTC(it->get<std::string>());
53 } 113 }
54 114
55 -int Sensor::getStatus() const 115 +bool Sensor::hasUserTest() const
56 { 116 {
57 - if (hasStatus()) 117 + return state.getValue().at("config").count("usertest") != 0;
  118 +}
  119 +void Sensor::setUserTest(bool enabled)
  120 +{
  121 + sendPutRequest("/config", nlohmann::json {{"usertest", enabled}}, CURRENT_FILE_INFO);
  122 +}
  123 +
  124 +bool Sensor::hasURL() const
  125 +{
  126 + return state.getValue().at("config").count("url") != 0;
  127 +}
  128 +std::string Sensor::getURL() const
  129 +{
  130 + return state.getValue().at("config").at("url").get<std::string>();
  131 +}
  132 +void Sensor::setURL(const std::string& url)
  133 +{
  134 + sendPutRequest("/config", nlohmann::json {{"url", url}}, CURRENT_FILE_INFO);
  135 +}
  136 +
  137 +std::vector<std::string> Sensor::getPendingConfig() const
  138 +{
  139 + const nlohmann::json& config = state.getValue().at("config");
  140 + const auto pendingIt = config.find("pending");
  141 + if (pendingIt == config.end() || !pendingIt->is_array())
  142 + {
  143 + return {};
  144 + }
  145 + std::vector<std::string> result;
  146 + result.reserve(pendingIt->size());
  147 + for (const nlohmann::json& pending : *pendingIt)
58 { 148 {
59 - return state.getValue().at("state").at("status"); 149 + result.push_back(pending.get<std::string>());
60 } 150 }
61 - return 0; 151 + return result;
  152 +}
  153 +
  154 +bool Sensor::hasLEDIndication() const
  155 +{
  156 + return state.getValue().at("config").count("ledindication") != 0;
  157 +}
  158 +bool Sensor::getLEDIndication() const
  159 +{
  160 + return state.getValue().at("config").at("ledindication").get<bool>();
  161 +}
  162 +void Sensor::setLEDIndication(bool on)
  163 +{
  164 + sendPutRequest("/config", nlohmann::json {{"ledindication", on}}, CURRENT_FILE_INFO);
  165 +}
  166 +
  167 +nlohmann::json Sensor::getState() const
  168 +{
  169 + return state.getValue().at("state");
  170 +}
  171 +void Sensor::setStateAttribute(const std::string& key, const nlohmann::json& value)
  172 +{
  173 + sendPutRequest("/state", nlohmann::json {{"key", value}}, CURRENT_FILE_INFO);
62 } 174 }
63 175
64 -bool Sensor::hasButtonEvent() const 176 +bool Sensor::isCertified() const
65 { 177 {
66 - return state.getValue().at("state").count("buttonevent") != 0; 178 + nlohmann::json certified = utils::safeGetMember(state.getValue(), "capabilities", "certified");
  179 + return certified.is_boolean() && certified.get<bool>();
67 } 180 }
68 181
69 -bool Sensor::hasStatus() const 182 +bool Sensor::isPrimary() const
70 { 183 {
71 - return state.getValue().at("state").count("status") != 0; 184 + nlohmann::json primary = utils::safeGetMember(state.getValue(), "capabilities", "primary");
  185 + return primary.is_boolean() && primary.get<bool>();
72 } 186 }
73 187
74 Sensor::Sensor(int id, const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration) 188 Sensor::Sensor(int id, const HueCommandAPI& commands, std::chrono::steady_clock::duration refreshDuration)