// 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 #include #include #include 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& 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, "invalid_parameter_value", "Invalid parameters"); cmd->Abort(error.get(), nullptr); } void OnSetBrightnessCommand(const std::weak_ptr& 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, "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 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; }