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
12namespace {
13
14const 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
159const 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
168const 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.
174class LightHandler {
175 public:
176  LightHandler() = default;
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:
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
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
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
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
305int 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