| // 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" | |
| } | |
| }, | |
| "errors": ["tempOutOfRange", "unsupportedUnits"] | |
| } | |
| }, | |
| "state": { | |
| "supportedUnits": { | |
| "type": "array", | |
| "items": { | |
| "type": "string", | |
| "enum": [ "celsius", "fahrenheit", "kelvin" ] | |
| }, | |
| "minItems": 1, | |
| "uniqueItems": true, | |
| "isRequired": true | |
| }, | |
| "units": { | |
| "type": "string", | |
| "enum": [ "celsius", "fahrenheit", "kelvin" ], | |
| "isRequired": true | |
| }, | |
| "tempSetting": { | |
| "type": "number", | |
| "isRequired": true | |
| }, | |
| "maxTempSetting": { | |
| "type": "number", | |
| "isRequired": true | |
| }, | |
| "minTempSetting": { | |
| "type": "number", | |
| "isRequired": true | |
| } | |
| } | |
| }, | |
| "temperatureSensor": { | |
| "commands": { | |
| "setConfig": { | |
| "minimalRole": "user", | |
| "parameters": { | |
| "units": { | |
| "type": "string" | |
| } | |
| }, | |
| "errors": ["unsupportedUnits"] | |
| } | |
| }, | |
| "state": { | |
| "supportedUnits": { | |
| "type": "array", | |
| "items": { | |
| "type": "string", | |
| "enum": [ | |
| "celsius", | |
| "fahrenheit", | |
| "kelvin" | |
| ] | |
| }, | |
| "minItems": 1, | |
| "uniqueItems": true, | |
| "isRequired": true | |
| }, | |
| "units": { | |
| "type": "string", | |
| "enum": [ "celsius", "fahrenheit", "kelvin" ], | |
| "isRequired": true | |
| }, | |
| "value": { | |
| "type": "number", | |
| "isRequired": true | |
| } | |
| } | |
| }, | |
| "brightness": { | |
| "commands": { | |
| "setConfig": { | |
| "minimalRole": "user", | |
| "parameters": { | |
| "brightness": { | |
| "type": "integer", | |
| "minimum": 0, | |
| "maximum": 100 | |
| } | |
| } | |
| } | |
| }, | |
| "state": { | |
| "brightness": { | |
| "type": "integer", | |
| "isRequired": true, | |
| "minimum": 0, | |
| "maximum": 100 | |
| } | |
| } | |
| } | |
| })"; | |
| 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; | |
| } |