Oven virtual device sample initial commit. Used as weave device for CES demo. Virtual oven implements temperatureSetting, temperatureSensor, and brightness traits. Change-Id: I33ec5c841ad102377166086668cbb0e1b78755dc Reviewed-on: https://weave-review.googlesource.com/1867 Reviewed-by: Peng Ying <pying@google.com>
diff --git a/examples/daemon/examples.gyp b/examples/daemon/examples.gyp index 2b497a5..d63c5e4 100644 --- a/examples/daemon/examples.gyp +++ b/examples/daemon/examples.gyp
@@ -8,7 +8,8 @@ 'light/daemon.gyp:weave_daemon_light', 'lock/daemon.gyp:weave_daemon_lock', 'ledflasher/daemon.gyp:weave_daemon_ledflasher', - 'speaker/daemon.gyp:weave_daemon_speaker' + 'speaker/daemon.gyp:weave_daemon_speaker', + 'oven/daemon.gyp:weave_daemon_oven', ] } ]
diff --git a/examples/daemon/oven/daemon.gyp b/examples/daemon/oven/daemon.gyp new file mode 100644 index 0000000..44b4798 --- /dev/null +++ b/examples/daemon/oven/daemon.gyp
@@ -0,0 +1,18 @@ +# Copyright 2015 The Weave Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +{ + 'targets': [ + { + 'target_name': 'weave_daemon_oven', + 'type': 'executable', + 'sources': [ + 'oven.cc', + ], + 'dependencies': [ + '<@(DEPTH)/libweave_standalone.gyp:libweave', + '<@(DEPTH)/examples/provider/provider.gyp:libweave_provider', + ] + } + ] +}
diff --git a/examples/daemon/oven/oven.cc b/examples/daemon/oven/oven.cc new file mode 100644 index 0000000..79fc925 --- /dev/null +++ b/examples/daemon/oven/oven.cc
@@ -0,0 +1,263 @@ +// Copyright 2015 The Weave Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "examples/daemon/common/daemon.h" + +#include <weave/device.h> +#include <weave/provider/task_runner.h> + +#include <base/bind.h> +#include <base/memory/weak_ptr.h> + +namespace { +// Time for sensor temperature to match setting temperature +const double kWarmUpTime = 60.0; +// Oven max temp +const double kMaxTemp = 300.0; +// Oven min temp +const double kMinTemp = 20.0; + +const char kTraits[] = R"({ + "temperatureSetting": { + "commands": { + "setConfig": { + "minimalRole": "user", + "parameters": { + "units": { + "type": "string" + }, + "tempSetting": { + "type": "number" + } + } + } + }, + "state": { + "supportedUnits": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "celsius", + "fahrenheit", + "kelvin" + ] + } + }, + "units": { + "type": "string" + }, + "tempSetting": { + "type": "number" + }, + "maxTempSetting": { + "type": "number" + }, + "minTempSetting": { + "type": "number" + } + } + }, + "temperatureSensor": { + "state": { + "supportedUnits": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "celsius", + "fahrenheit", + "kelvin" + ] + } + }, + "units": { + "type": "string" + }, + "value": { + "type": "number" + } + } + }, + "brightness": { + "commands": { + "setConfig": { + "minimalRole": "user", + "parameters": { + "brightness": { + "type": "integer", + "minimum": 0, + "maximum": 100 + } + } + } + }, + "state": { + "brightness": { + "type": "number" + } + } + } +})"; + +const char kComponent[] = "oven"; +} // anonymous namespace + +// OvenHandler is a virtual oven example +// It implements the following commands from traits: +// - temperatureSetting: sets the temperature for the oven +// - brightness: sets the brightness of the oven light +// It exposes the following states from traits: +// - temperatureSetting: temperature setting for the oven +// - temperatureSensor: current oven temperature +// - brightness: current oven brightness +class OvenHandler { + public: + OvenHandler(weave::provider::TaskRunner* task_runner) + : task_runner_{task_runner} {} + + void Register(weave::Device* device) { + device_ = device; + + device->AddTraitDefinitionsFromJson(kTraits); + CHECK(device->AddComponent( + kComponent, {"temperatureSetting", "temperatureSensor", "brightness"}, + nullptr)); + + UpdateOvenState(); + + device->AddCommandHandler(kComponent, "temperatureSetting.setConfig", + base::Bind(&OvenHandler::OnSetTempCommand, + weak_ptr_factory_.GetWeakPtr())); + + device->AddCommandHandler(kComponent, "brightness.setConfig", + base::Bind(&OvenHandler::OnSetBrightnessCommand, + weak_ptr_factory_.GetWeakPtr())); + } + +private: + void OnSetTempCommand(const std::weak_ptr<weave::Command>& command) { + auto cmd = command.lock(); + if (!cmd) + return; + LOG(INFO) << "received command: " << cmd->GetName(); + + const auto& params = cmd->GetParameters(); + std::string units; + double temp; + + if (params.GetString("units", &units) && + params.GetDouble("tempSetting", &temp)) { + units_ = units; + target_temperature_ = temp; + + UpdateOvenState(); + + cmd->Complete({}, nullptr); + LOG(INFO) << cmd->GetName() << " updated oven, matching temp"; + + if (target_temperature_ != current_temperature_ && !is_match_ticking_) { + double tickIncrement = ((target_temperature_ - current_temperature_) / + kWarmUpTime); + DoTick(tickIncrement); + } + return; + } + + weave::ErrorPtr error; + weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value", + "Invalid parameters"); + cmd->Abort(error.get(), nullptr); + } + + void OnSetBrightnessCommand(const std::weak_ptr<weave::Command>& command) { + auto cmd = command.lock(); + if (!cmd) + return; + LOG(INFO) << "received command: " << cmd->GetName(); + + const auto& params = cmd->GetParameters(); + + int brightness; + if (params.GetInteger("brightness", &brightness)) { + brightness_ = brightness; + + UpdateOvenState(); + + cmd->Complete({}, nullptr); + return; + } + + weave::ErrorPtr error; + weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value", + "Invalid parameters"); + cmd->Abort(error.get(), nullptr); + } + + void UpdateOvenState() { + base::DictionaryValue state; + base::ListValue supportedUnits; + supportedUnits.AppendStrings({"celsius"}); + + state.SetString("temperatureSensor.units", units_); + state.SetDouble("temperatureSensor.value", current_temperature_); + state.Set("temperatureSensor.supportedUnits", supportedUnits.DeepCopy()); + + state.SetString("temperatureSetting.units", units_); + state.SetDouble("temperatureSetting.tempSetting", target_temperature_); + state.Set("temperatureSetting.supportedUnits", supportedUnits.DeepCopy()); + state.SetDouble("temperatureSetting.maxTempSetting", kMaxTemp); + state.SetDouble("temperatureSetting.minTempSetting", kMinTemp); + + state.SetInteger("brightness.brightness", brightness_); + + device_->SetStateProperties(kComponent, state, nullptr); + } + + void DoTick(double tickIncrement) { + LOG(INFO) << "Oven matching temp tick"; + + if (std::fabs(target_temperature_ - current_temperature_) >= + tickIncrement) { + is_match_ticking_ = true; + current_temperature_ += tickIncrement; + UpdateOvenState(); + task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&OvenHandler::DoTick, + weak_ptr_factory_.GetWeakPtr(), tickIncrement), + base::TimeDelta::FromSeconds(1)); + return; + } + + is_match_ticking_ = false; + current_temperature_ = target_temperature_; + UpdateOvenState(); + + LOG(INFO) << "Oven temp matched"; + } + + weave::Device* device_{nullptr}; + weave::provider::TaskRunner* task_runner_{nullptr}; + + std::string units_ = "celsius"; + double target_temperature_ = 0.0; + double current_temperature_ = 0.0; + int brightness_ = 0; + bool is_match_ticking_ = false; + + base::WeakPtrFactory<OvenHandler> weak_ptr_factory_{this}; +}; + +int main(int argc, char** argv) { + Daemon::Options opts; + if (!opts.Parse(argc, argv)) { + Daemon::Options::ShowUsage(argv[0]); + return 1; + } + Daemon daemon{opts}; + OvenHandler handler{daemon.GetTaskRunner()}; + handler.Register(daemon.GetDevice()); + daemon.Run(); + return 0; +}