1 // Copyright 2015 The Weave Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "examples/daemon/common/daemon.h"
6 
7 #include <weave/device.h>
8 
9 #include <base/bind.h>
10 #include <base/memory/weak_ptr.h>
11 
12 namespace {
13 
14 const char kTraits[] = R"({
15   "onOff": {
16     "commands": {
17       "setConfig": {
18         "minimalRole": "user",
19         "parameters": {
20           "state": {
21             "type": "string",
22             "enum": [ "on", "standby" ]
23           }
24         }
25       }
26     },
27     "state": {
28       "state": {
29         "type": "string",
30         "enum": [ "on", "standby" ],
31         "isRequired": true
32       }
33     }
34   },
35   "brightness": {
36     "commands": {
37       "setConfig": {
38         "minimalRole": "user",
39         "parameters": {
40           "brightness": {
41             "type": "integer",
42             "minimum": 0,
43             "maximum": 100
44           }
45         }
46       }
47     },
48     "state": {
49       "brightness": {
50         "type": "integer",
51         "isRequired": true,
52         "minimum": 0,
53         "maximum": 100
54       }
55     }
56   },
57   "colorXY": {
58     "commands": {
59       "setConfig": {
60         "minimalRole": "user",
61         "parameters": {
62           "colorSetting": {
63             "type": "object",
64             "required": [
65               "colorX",
66               "colorY"
67             ],
68             "properties": {
69               "colorX": {
70                 "type": "number",
71                 "minimum": 0.0,
72                 "maximum": 1.0
73               },
74               "colorY": {
75                 "type": "number",
76                 "minimum": 0.0,
77                 "maximum": 1.0
78               }
79             },
80             "additionalProperties": false
81           }
82         },
83         "errors": ["colorOutOfRange"]
84       }
85     },
86     "state": {
87       "colorSetting": {
88         "type": "object",
89         "isRequired": true,
90         "required": [ "colorX", "colorY" ],
91         "properties": {
92           "colorX": {
93             "type": "number",
94             "minimum": 0.0,
95             "maximum": 1.0
96           },
97           "colorY": {
98             "type": "number",
99             "minimum": 0.0,
100             "maximum": 1.0
101           }
102         }
103       },
104       "colorCapRed": {
105         "type": "object",
106         "isRequired": true,
107         "required": [ "colorX", "colorY" ],
108         "properties": {
109           "colorX": {
110             "type": "number",
111             "minimum": 0.0,
112             "maximum": 1.0
113           },
114           "colorY": {
115             "type": "number",
116             "minimum": 0.0,
117             "maximum": 1.0
118           }
119         }
120       },
121       "colorCapGreen": {
122         "type": "object",
123         "isRequired": true,
124         "required": [ "colorX", "colorY" ],
125         "properties": {
126           "colorX": {
127             "type": "number",
128             "minimum": 0.0,
129             "maximum": 1.0
130           },
131           "colorY": {
132             "type": "number",
133             "minimum": 0.0,
134             "maximum": 1.0
135           }
136         }
137       },
138       "colorCapBlue": {
139         "type": "object",
140         "isRequired": true,
141         "required": [ "colorX", "colorY" ],
142         "properties": {
143           "colorX": {
144             "type": "number",
145             "minimum": 0.0,
146             "maximum": 1.0
147           },
148           "colorY": {
149             "type": "number",
150             "minimum": 0.0,
151             "maximum": 1.0
152           }
153         }
154       }
155     }
156   }
157 })";
158 
159 const char kDefaultState[] = R"({
160   "colorXY": {
161     "colorSetting": {"colorX": 0, "colorY": 0},
162     "colorCapRed":  {"colorX": 0.674, "colorY": 0.322},
163     "colorCapGreen":{"colorX": 0.408, "colorY": 0.517},
164     "colorCapBlue": {"colorX": 0.168, "colorY": 0.041}
165   }
166 })";
167 
168 const char kComponent[] = "light";
169 
170 }  // anonymous namespace
171 
172 // LightHandler is a command handler example that shows
173 // how to handle commands for a Weave light.
174 class LightHandler {
175  public:
176   LightHandler() = default;
Register(weave::Device * device)177   void Register(weave::Device* device) {
178     device_ = device;
179 
180     device->AddTraitDefinitionsFromJson(kTraits);
181     CHECK(device->AddComponent(kComponent, {"onOff", "brightness", "colorXY"},
182                                nullptr));
183     CHECK(
184         device->SetStatePropertiesFromJson(kComponent, kDefaultState, nullptr));
185     UpdateLightState();
186 
187     device->AddCommandHandler(kComponent, "onOff.setConfig",
188                               base::Bind(&LightHandler::OnOnOffSetConfig,
189                                          weak_ptr_factory_.GetWeakPtr()));
190     device->AddCommandHandler(kComponent, "brightness.setConfig",
191                               base::Bind(&LightHandler::OnBrightnessSetConfig,
192                                          weak_ptr_factory_.GetWeakPtr()));
193     device->AddCommandHandler(kComponent, "colorXY.setConfig",
194                               base::Bind(&LightHandler::OnColorXYSetConfig,
195                                          weak_ptr_factory_.GetWeakPtr()));
196   }
197 
198  private:
OnBrightnessSetConfig(const std::weak_ptr<weave::Command> & command)199   void OnBrightnessSetConfig(const std::weak_ptr<weave::Command>& command) {
200     auto cmd = command.lock();
201     if (!cmd)
202       return;
203     LOG(INFO) << "received command: " << cmd->GetName();
204     const auto& params = cmd->GetParameters();
205     int32_t brightness_value = 0;
206     if (params.GetInteger("brightness", &brightness_value)) {
207       // Display this command in terminal.
208       LOG(INFO) << cmd->GetName() << " brightness: " << brightness_value;
209 
210       if (brightness_state_ != brightness_value) {
211         brightness_state_ = brightness_value;
212         UpdateLightState();
213       }
214       cmd->Complete({}, nullptr);
215       return;
216     }
217     weave::ErrorPtr error;
218     weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
219                         "Invalid parameters");
220     cmd->Abort(error.get(), nullptr);
221   }
222 
OnOnOffSetConfig(const std::weak_ptr<weave::Command> & command)223   void OnOnOffSetConfig(const std::weak_ptr<weave::Command>& command) {
224     auto cmd = command.lock();
225     if (!cmd)
226       return;
227     LOG(INFO) << "received command: " << cmd->GetName();
228     const auto& params = cmd->GetParameters();
229     std::string requested_state;
230     if (params.GetString("state", &requested_state)) {
231       LOG(INFO) << cmd->GetName() << " state: " << requested_state;
232 
233       bool new_light_status = requested_state == "on";
234       if (new_light_status != light_status_) {
235         light_status_ = new_light_status;
236 
237         LOG(INFO) << "Light is now: " << (light_status_ ? "ON" : "OFF");
238         UpdateLightState();
239       }
240       cmd->Complete({}, nullptr);
241       return;
242     }
243     weave::ErrorPtr error;
244     weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
245                         "Invalid parameters");
246     cmd->Abort(error.get(), nullptr);
247   }
248 
OnColorXYSetConfig(const std::weak_ptr<weave::Command> & command)249   void OnColorXYSetConfig(const std::weak_ptr<weave::Command>& command) {
250     auto cmd = command.lock();
251     if (!cmd)
252       return;
253     LOG(INFO) << "received command: " << cmd->GetName();
254     const auto& params = cmd->GetParameters();
255     const base::DictionaryValue* colorXY = nullptr;
256     if (params.GetDictionary("colorSetting", &colorXY)) {
257       bool updateState = false;
258       double X = 0.0;
259       double Y = 0.0;
260       if (colorXY->GetDouble("colorX", &X)) {
261         color_X_ = X;
262         updateState = true;
263       }
264 
265       if (colorXY->GetDouble("colorY", &Y)) {
266         color_Y_ = Y;
267         updateState = true;
268       }
269 
270       if (updateState)
271         UpdateLightState();
272 
273       cmd->Complete({}, nullptr);
274       return;
275     }
276 
277     weave::ErrorPtr error;
278     weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
279                         "Invalid parameters");
280     cmd->Abort(error.get(), nullptr);
281   }
282 
UpdateLightState()283   void UpdateLightState() {
284     base::DictionaryValue state;
285     state.SetString("onOff.state", light_status_ ? "on" : "standby");
286     state.SetInteger("brightness.brightness", brightness_state_);
287 
288     std::unique_ptr<base::DictionaryValue> colorXY(new base::DictionaryValue());
289     colorXY->SetDouble("colorX", color_X_);
290     colorXY->SetDouble("colorY", color_Y_);
291     state.Set("colorXY.colorSetting", colorXY.release());
292     device_->SetStateProperties(kComponent, state, nullptr);
293   }
294 
295   weave::Device* device_{nullptr};
296 
297   // Simulate the state of the light.
298   bool light_status_{false};
299   int32_t brightness_state_{0};
300   double color_X_{0.0};
301   double color_Y_{0.0};
302   base::WeakPtrFactory<LightHandler> weak_ptr_factory_{this};
303 };
304 
main(int argc,char ** argv)305 int main(int argc, char** argv) {
306   Daemon::Options opts;
307   opts.model_id_ = "AIAAA";
308   if (!opts.Parse(argc, argv)) {
309     Daemon::Options::ShowUsage(argv[0]);
310     return 1;
311   }
312   Daemon daemon{opts};
313   LightHandler handler;
314   handler.Register(daemon.GetDevice());
315   daemon.Run();
316   return 0;
317 }
318