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