288 lines
7.6 KiB
C++
288 lines
7.6 KiB
C++
// 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, "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, "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;
|
|
}
|