1aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// Copyright 2015 The Weave Authors. All rights reserved.
2aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// Use of this source code is governed by a BSD-style license that can be
3aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// found in the LICENSE file.
4aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
5aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying#include "examples/daemon/common/daemon.h"
6aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
7aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying#include <weave/device.h>
8aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying#include <weave/provider/task_runner.h>
9aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
10aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying#include <base/bind.h>
11aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying#include <base/memory/weak_ptr.h>
12aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
13aef87f5214d4e8b5924281d82dae2c8156f4203apeng yingnamespace {
14aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// Time for sensor temperature to match setting temperature
15aef87f5214d4e8b5924281d82dae2c8156f4203apeng yingconst double kWarmUpTime = 60.0;
16aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// Oven max temp
17aef87f5214d4e8b5924281d82dae2c8156f4203apeng yingconst double kMaxTemp = 300.0;
18aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// Oven min temp
19aef87f5214d4e8b5924281d82dae2c8156f4203apeng yingconst double kMinTemp = 20.0;
20aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
21aef87f5214d4e8b5924281d82dae2c8156f4203apeng yingconst char kTraits[] = R"({
22aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  "temperatureSetting": {
23aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    "commands": {
24aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "setConfig": {
25aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        "minimalRole": "user",
26aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        "parameters": {
27aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          "units": {
28aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying            "type": "string"
29aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          },
30aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          "tempSetting": {
31aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying            "type": "number"
32aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          }
338d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        },
348d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "errors": ["tempOutOfRange", "unsupportedUnits"]
35aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      }
36aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    },
37aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    "state": {
38aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "supportedUnits": {
39aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        "type": "array",
40aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        "items": {
41aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          "type": "string",
428d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko          "enum": [ "celsius", "fahrenheit", "kelvin" ]
438d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        },
448d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "minItems": 1,
458d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "uniqueItems": true,
468d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "isRequired": true
47aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      },
48aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "units": {
498d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "type": "string",
508d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "enum": [ "celsius", "fahrenheit", "kelvin" ],
518d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "isRequired": true
52aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      },
53aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "tempSetting": {
548d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "type": "number",
558d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "isRequired": true
56aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      },
57aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "maxTempSetting": {
588d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "type": "number",
598d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "isRequired": true
60aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      },
61aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "minTempSetting": {
628d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "type": "number",
638d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "isRequired": true
64aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      }
65aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    }
66aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  },
67aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  "temperatureSensor": {
688d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko    "commands": {
698d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko      "setConfig": {
708d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "minimalRole": "user",
718d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "parameters": {
728d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko          "units": {
738d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko            "type": "string"
748d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko          }
758d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        },
768d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "errors": ["unsupportedUnits"]
778d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko      }
788d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko    },
79aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    "state": {
80aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "supportedUnits": {
81aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        "type": "array",
82aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        "items": {
83aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          "type": "string",
84aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          "enum": [
85aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying            "celsius",
86aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying            "fahrenheit",
87aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying            "kelvin"
88aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          ]
898d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        },
908d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "minItems": 1,
918d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "uniqueItems": true,
928d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "isRequired": true
93aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      },
94aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "units": {
958d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "type": "string",
968d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "enum": [ "celsius", "fahrenheit", "kelvin" ],
978d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "isRequired": true
98aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      },
99aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "value": {
1008d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "type": "number",
1018d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "isRequired": true
102aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      }
103aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    }
104aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  },
105aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  "brightness": {
106aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    "commands": {
107aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "setConfig": {
108aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        "minimalRole": "user",
109aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        "parameters": {
110aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          "brightness": {
111aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying            "type": "integer",
112aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying            "minimum": 0,
113aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying            "maximum": 100
114aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          }
115aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        }
116aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      }
117aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    },
118aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    "state": {
119aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      "brightness": {
1208d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "type": "integer",
1218d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "isRequired": true,
1228d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "minimum": 0,
1238d0cfefae24985025a934ea5461a51472c59cfc0Alex Vakulenko        "maximum": 100
124aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      }
125aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    }
126aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  }
127aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying})";
128aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
129aef87f5214d4e8b5924281d82dae2c8156f4203apeng yingconst char kComponent[] = "oven";
130aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying}  // anonymous namespace
131aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
132aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// OvenHandler is a virtual oven example
133aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// It implements the following commands from traits:
134aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// - temperatureSetting: sets the temperature for the oven
135aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// - brightness: sets the brightness of the oven light
136aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// It exposes the following states from traits:
137aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// - temperatureSetting: temperature setting for the oven
138aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// - temperatureSensor: current oven temperature
139aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying// - brightness: current oven brightness
140aef87f5214d4e8b5924281d82dae2c8156f4203apeng yingclass OvenHandler {
141aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying public:
142aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  OvenHandler(weave::provider::TaskRunner* task_runner)
143aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      : task_runner_{task_runner} {}
144aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
145aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  void Register(weave::Device* device) {
146aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    device_ = device;
147aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
148aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    device->AddTraitDefinitionsFromJson(kTraits);
149aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    CHECK(device->AddComponent(
150aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        kComponent, {"temperatureSetting", "temperatureSensor", "brightness"},
151aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        nullptr));
152aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
153aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    UpdateOvenState();
154aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
155aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    device->AddCommandHandler(kComponent, "temperatureSetting.setConfig",
156aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying                              base::Bind(&OvenHandler::OnSetTempCommand,
157aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying                                         weak_ptr_factory_.GetWeakPtr()));
158aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
159aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    device->AddCommandHandler(kComponent, "brightness.setConfig",
160aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying                              base::Bind(&OvenHandler::OnSetBrightnessCommand,
161aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying                                         weak_ptr_factory_.GetWeakPtr()));
162aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  }
163aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
16434668e731bb194b443bc0e6029d6d3583f08de28Vitaly Buka private:
165aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  void OnSetTempCommand(const std::weak_ptr<weave::Command>& command) {
166aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    auto cmd = command.lock();
167aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    if (!cmd)
168aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      return;
169aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    LOG(INFO) << "received command: " << cmd->GetName();
170aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
171aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    const auto& params = cmd->GetParameters();
172aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    std::string units;
173aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    double temp;
174aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
175aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    if (params.GetString("units", &units) &&
176aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        params.GetDouble("tempSetting", &temp)) {
177aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      units_ = units;
178aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      target_temperature_ = temp;
179aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
180aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      UpdateOvenState();
181aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
182aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      cmd->Complete({}, nullptr);
183aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      LOG(INFO) << cmd->GetName() << " updated oven, matching temp";
184aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
185aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      if (target_temperature_ != current_temperature_ && !is_match_ticking_) {
18634668e731bb194b443bc0e6029d6d3583f08de28Vitaly Buka        double tickIncrement =
18734668e731bb194b443bc0e6029d6d3583f08de28Vitaly Buka            ((target_temperature_ - current_temperature_) / kWarmUpTime);
188aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        DoTick(tickIncrement);
189aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      }
190aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      return;
191aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    }
192aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
193aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    weave::ErrorPtr error;
19448a8669ddc2e8d785aad9ad18a5abbf8f1224fdeVitaly Buka    weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
195aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying                        "Invalid parameters");
196aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    cmd->Abort(error.get(), nullptr);
197aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  }
198aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
199aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  void OnSetBrightnessCommand(const std::weak_ptr<weave::Command>& command) {
200aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    auto cmd = command.lock();
201aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    if (!cmd)
202aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      return;
203aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    LOG(INFO) << "received command: " << cmd->GetName();
204aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
205aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    const auto& params = cmd->GetParameters();
206aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
207aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    int brightness;
208aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    if (params.GetInteger("brightness", &brightness)) {
209aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      brightness_ = brightness;
210aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
211aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      UpdateOvenState();
212aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
213aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      cmd->Complete({}, nullptr);
214aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      return;
215aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    }
216aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
217aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    weave::ErrorPtr error;
21848a8669ddc2e8d785aad9ad18a5abbf8f1224fdeVitaly Buka    weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
219aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying                        "Invalid parameters");
220aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    cmd->Abort(error.get(), nullptr);
221aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  }
222aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
223aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  void UpdateOvenState() {
224aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    base::DictionaryValue state;
225aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    base::ListValue supportedUnits;
226aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    supportedUnits.AppendStrings({"celsius"});
227aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
228aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    state.SetString("temperatureSensor.units", units_);
229aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    state.SetDouble("temperatureSensor.value", current_temperature_);
230aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    state.Set("temperatureSensor.supportedUnits", supportedUnits.DeepCopy());
231aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
232aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    state.SetString("temperatureSetting.units", units_);
233aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    state.SetDouble("temperatureSetting.tempSetting", target_temperature_);
234aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    state.Set("temperatureSetting.supportedUnits", supportedUnits.DeepCopy());
235aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    state.SetDouble("temperatureSetting.maxTempSetting", kMaxTemp);
236aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    state.SetDouble("temperatureSetting.minTempSetting", kMinTemp);
237aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
238aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    state.SetInteger("brightness.brightness", brightness_);
239aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
240aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    device_->SetStateProperties(kComponent, state, nullptr);
241aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  }
242aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
243aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  void DoTick(double tickIncrement) {
244aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    LOG(INFO) << "Oven matching temp tick";
245aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
246aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    if (std::fabs(target_temperature_ - current_temperature_) >=
247aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying        tickIncrement) {
248aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      is_match_ticking_ = true;
249aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      current_temperature_ += tickIncrement;
250aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      UpdateOvenState();
251aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      task_runner_->PostDelayedTask(
252aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          FROM_HERE, base::Bind(&OvenHandler::DoTick,
253aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying                                weak_ptr_factory_.GetWeakPtr(), tickIncrement),
254aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying          base::TimeDelta::FromSeconds(1));
255aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying      return;
256aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    }
257aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
258aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    is_match_ticking_ = false;
259aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    current_temperature_ = target_temperature_;
260aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    UpdateOvenState();
261aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
262aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    LOG(INFO) << "Oven temp matched";
263aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  }
264aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
265aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  weave::Device* device_{nullptr};
266aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  weave::provider::TaskRunner* task_runner_{nullptr};
267aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
268aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  std::string units_ = "celsius";
269aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  double target_temperature_ = 0.0;
270aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  double current_temperature_ = 0.0;
271aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  int brightness_ = 0;
272aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  bool is_match_ticking_ = false;
273aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
274aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  base::WeakPtrFactory<OvenHandler> weak_ptr_factory_{this};
275aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying};
276aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying
277aef87f5214d4e8b5924281d82dae2c8156f4203apeng yingint main(int argc, char** argv) {
278aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  Daemon::Options opts;
279aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  if (!opts.Parse(argc, argv)) {
280aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    Daemon::Options::ShowUsage(argv[0]);
281aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying    return 1;
282aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  }
283aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  Daemon daemon{opts};
284aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  OvenHandler handler{daemon.GetTaskRunner()};
285aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  handler.Register(daemon.GetDevice());
286aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  daemon.Run();
287aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying  return 0;
288aef87f5214d4e8b5924281d82dae2c8156f4203apeng ying}
289