oven.cc revision aef87f5214d4e8b5924281d82dae2c8156f4203a
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#include <weave/provider/task_runner.h>
9
10#include <base/bind.h>
11#include <base/memory/weak_ptr.h>
12
13namespace {
14// Time for sensor temperature to match setting temperature
15const double kWarmUpTime = 60.0;
16// Oven max temp
17const double kMaxTemp = 300.0;
18// Oven min temp
19const double kMinTemp = 20.0;
20
21const char kTraits[] = R"({
22  "temperatureSetting": {
23    "commands": {
24      "setConfig": {
25        "minimalRole": "user",
26        "parameters": {
27          "units": {
28            "type": "string"
29          },
30          "tempSetting": {
31            "type": "number"
32          }
33        }
34      }
35    },
36    "state": {
37      "supportedUnits": {
38        "type": "array",
39        "items": {
40          "type": "string",
41          "enum": [
42            "celsius",
43            "fahrenheit",
44            "kelvin"
45          ]
46        }
47      },
48      "units": {
49        "type": "string"
50      },
51      "tempSetting": {
52        "type": "number"
53      },
54      "maxTempSetting": {
55        "type": "number"
56      },
57      "minTempSetting": {
58        "type": "number"
59      }
60    }
61  },
62  "temperatureSensor": {
63    "state": {
64      "supportedUnits": {
65        "type": "array",
66        "items": {
67          "type": "string",
68          "enum": [
69            "celsius",
70            "fahrenheit",
71            "kelvin"
72          ]
73        }
74      },
75      "units": {
76        "type": "string"
77      },
78      "value": {
79        "type": "number"
80      }
81    }
82  },
83  "brightness": {
84    "commands": {
85      "setConfig": {
86        "minimalRole": "user",
87        "parameters": {
88          "brightness": {
89            "type": "integer",
90            "minimum": 0,
91            "maximum": 100
92          }
93        }
94      }
95    },
96    "state": {
97      "brightness": {
98        "type": "number"
99      }
100    }
101  }
102})";
103
104const char kComponent[] = "oven";
105}  // anonymous namespace
106
107// OvenHandler is a virtual oven example
108// It implements the following commands from traits:
109// - temperatureSetting: sets the temperature for the oven
110// - brightness: sets the brightness of the oven light
111// It exposes the following states from traits:
112// - temperatureSetting: temperature setting for the oven
113// - temperatureSensor: current oven temperature
114// - brightness: current oven brightness
115class OvenHandler {
116 public:
117  OvenHandler(weave::provider::TaskRunner* task_runner)
118      : task_runner_{task_runner} {}
119
120  void Register(weave::Device* device) {
121    device_ = device;
122
123    device->AddTraitDefinitionsFromJson(kTraits);
124    CHECK(device->AddComponent(
125        kComponent, {"temperatureSetting", "temperatureSensor", "brightness"},
126        nullptr));
127
128    UpdateOvenState();
129
130    device->AddCommandHandler(kComponent, "temperatureSetting.setConfig",
131                              base::Bind(&OvenHandler::OnSetTempCommand,
132                                         weak_ptr_factory_.GetWeakPtr()));
133
134    device->AddCommandHandler(kComponent, "brightness.setConfig",
135                              base::Bind(&OvenHandler::OnSetBrightnessCommand,
136                                         weak_ptr_factory_.GetWeakPtr()));
137  }
138
139private:
140  void OnSetTempCommand(const std::weak_ptr<weave::Command>& command) {
141    auto cmd = command.lock();
142    if (!cmd)
143      return;
144    LOG(INFO) << "received command: " << cmd->GetName();
145
146    const auto& params = cmd->GetParameters();
147    std::string units;
148    double temp;
149
150    if (params.GetString("units", &units) &&
151        params.GetDouble("tempSetting", &temp)) {
152      units_ = units;
153      target_temperature_ = temp;
154
155      UpdateOvenState();
156
157      cmd->Complete({}, nullptr);
158      LOG(INFO) << cmd->GetName() << " updated oven, matching temp";
159
160      if (target_temperature_ != current_temperature_ && !is_match_ticking_) {
161        double tickIncrement = ((target_temperature_ - current_temperature_) /
162            kWarmUpTime);
163        DoTick(tickIncrement);
164      }
165      return;
166    }
167
168    weave::ErrorPtr error;
169    weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value",
170                        "Invalid parameters");
171    cmd->Abort(error.get(), nullptr);
172  }
173
174  void OnSetBrightnessCommand(const std::weak_ptr<weave::Command>& command) {
175    auto cmd = command.lock();
176    if (!cmd)
177      return;
178    LOG(INFO) << "received command: " << cmd->GetName();
179
180    const auto& params = cmd->GetParameters();
181
182    int brightness;
183    if (params.GetInteger("brightness", &brightness)) {
184      brightness_ = brightness;
185
186      UpdateOvenState();
187
188      cmd->Complete({}, nullptr);
189      return;
190    }
191
192    weave::ErrorPtr error;
193    weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value",
194                        "Invalid parameters");
195    cmd->Abort(error.get(), nullptr);
196  }
197
198  void UpdateOvenState() {
199    base::DictionaryValue state;
200    base::ListValue supportedUnits;
201    supportedUnits.AppendStrings({"celsius"});
202
203    state.SetString("temperatureSensor.units", units_);
204    state.SetDouble("temperatureSensor.value", current_temperature_);
205    state.Set("temperatureSensor.supportedUnits", supportedUnits.DeepCopy());
206
207    state.SetString("temperatureSetting.units", units_);
208    state.SetDouble("temperatureSetting.tempSetting", target_temperature_);
209    state.Set("temperatureSetting.supportedUnits", supportedUnits.DeepCopy());
210    state.SetDouble("temperatureSetting.maxTempSetting", kMaxTemp);
211    state.SetDouble("temperatureSetting.minTempSetting", kMinTemp);
212
213    state.SetInteger("brightness.brightness", brightness_);
214
215    device_->SetStateProperties(kComponent, state, nullptr);
216  }
217
218  void DoTick(double tickIncrement) {
219    LOG(INFO) << "Oven matching temp tick";
220
221    if (std::fabs(target_temperature_ - current_temperature_) >=
222        tickIncrement) {
223      is_match_ticking_ = true;
224      current_temperature_ += tickIncrement;
225      UpdateOvenState();
226      task_runner_->PostDelayedTask(
227          FROM_HERE, base::Bind(&OvenHandler::DoTick,
228                                weak_ptr_factory_.GetWeakPtr(), tickIncrement),
229          base::TimeDelta::FromSeconds(1));
230      return;
231    }
232
233    is_match_ticking_ = false;
234    current_temperature_ = target_temperature_;
235    UpdateOvenState();
236
237    LOG(INFO) << "Oven temp matched";
238  }
239
240  weave::Device* device_{nullptr};
241  weave::provider::TaskRunner* task_runner_{nullptr};
242
243  std::string units_ = "celsius";
244  double target_temperature_ = 0.0;
245  double current_temperature_ = 0.0;
246  int brightness_ = 0;
247  bool is_match_ticking_ = false;
248
249  base::WeakPtrFactory<OvenHandler> weak_ptr_factory_{this};
250};
251
252int main(int argc, char** argv) {
253  Daemon::Options opts;
254  if (!opts.Parse(argc, argv)) {
255    Daemon::Options::ShowUsage(argv[0]);
256    return 1;
257  }
258  Daemon daemon{opts};
259  OvenHandler handler{daemon.GetTaskRunner()};
260  handler.Register(daemon.GetDevice());
261  daemon.Run();
262  return 0;
263}
264