aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Vakulenko <avakulenko@google.com>2016-04-07 18:45:14 +0000
committerandroid-build-merger <android-build-merger@google.com>2016-04-07 18:45:14 +0000
commit42e265469608501a577f0125cc10b20597dc23d5 (patch)
treefcb8970cd393990638c604abd533856dc9a914bb
parentc76ba0bda5cd40af263467cc1ecdac0c537f914a (diff)
parent1ce13aa8c408baee70fac6bd1b0f19ec2db1bfc7 (diff)
downloadlibweave-42e265469608501a577f0125cc10b20597dc23d5.tar.gz
Merge remote-tracking branch \'weave/master\' into \'weave/aosp-master\' am: 8c81944 am: 6677a30
am: 1ce13aa * commit '1ce13aa8c408baee70fac6bd1b0f19ec2db1bfc7': libweave: Always fetch commands from server, even if XMPP delivers JSON libweave: Remove backup polling (30 minute poll interval) clean up example/test_device clashes disable builtin rules add standard "check" target readme: document cross-compiling for end users Add "make coverage" target to build code coverage. Add general-use-and-purpose comment for Device interface. create generic test device for multiple traits testing. libuweave: Fix break on Android toolchain Change-Id: I6d04706720e94a9b310f0552a75a4eeaa823edb6
-rw-r--r--Makefile9
-rw-r--r--README.md23
-rw-r--r--examples/examples.mk42
-rw-r--r--include/weave/device.h19
-rw-r--r--src/device_registration_info.cc58
-rw-r--r--src/device_registration_info.h4
-rw-r--r--tests.mk18
-rw-r--r--tests_schema/daemon/testdevice/standard_traits.h216
-rw-r--r--tests_schema/daemon/testdevice/testdevice.cc277
-rw-r--r--tests_schema/tests_schema.mk45
-rw-r--r--third_party/third_party.mk11
11 files changed, 657 insertions, 65 deletions
diff --git a/Makefile b/Makefile
index e348fd8..0eff8e1 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+# Disable all builtin rules first as we don't use any of them (we define all
+# rules/targets ourselves, nor do we want to rely on them.
+MAKEFLAGS += --no-builtin-rules
+.SUFFIXES:
+
# Run make with BUILD_MODE=Release for release.
BUILD_MODE ?= Debug
@@ -76,7 +81,7 @@ DEFS_TEST := \
out/$(BUILD_MODE)/libweave.so : out/$(BUILD_MODE)/libweave_common.a
$(CXX) -shared -Wl,-soname=libweave.so -o $@ -Wl,--whole-archive $^ -Wl,--no-whole-archive -lcrypto -lexpat -lpthread -lrt
-include cross.mk file_lists.mk third_party/third_party.mk examples/examples.mk tests.mk
+include cross.mk file_lists.mk third_party/third_party.mk examples/examples.mk tests.mk tests_schema/tests_schema.mk
###
# src/
@@ -94,7 +99,7 @@ out/$(BUILD_MODE)/libweave_common.a : $(weave_obj_files) $(third_party_chromium_
all-libs : out/$(BUILD_MODE)/libweave.so
all-tests : out/$(BUILD_MODE)/libweave_exports_testrunner out/$(BUILD_MODE)/libweave_testrunner
-all : all-libs all-examples all-tests
+all : all-libs all-examples all-tests all-testdevices
clean :
rm -rf out
diff --git a/README.md b/README.md
index 428b0f5..c179e61 100644
--- a/README.md
+++ b/README.md
@@ -128,6 +128,29 @@ See [the examples README](/examples/daemon/README.md) for details.
### Cross-compiling
+#### libweave users
+
+In order to cross-compile, all you need to configure is CC/CXX/AR.
+
+```
+make CC=your-cc CXX=your-cxx AR=your-ar
+```
+
+So if you have a toolchain in a path like `/opt/vendor/bin/arm-linux-gcc`, do:
+
+```
+make \
+ CC=/opt/vendor/bin/arm-linux-gcc \
+ CXX=/opt/vendor/bin/arm-linux-g++ \
+ AR=/opt/vendor/bin/arm-linux-ar
+```
+
+#### libweave developers
+
+*** note
+**Note:** This is only for developers who are hacking on libweave itself.
+***
+
The build supports transparently downloading & using a few cross-compilers.
Just add `cross-<arch>` to the command line in addition to the target you
want to actually build.
diff --git a/examples/examples.mk b/examples/examples.mk
index 48a1210..555322c 100644
--- a/examples/examples.mk
+++ b/examples/examples.mk
@@ -7,16 +7,6 @@
examples_provider_obj_files := $(EXAMPLES_PROVIDER_SRC_FILES:%.cc=out/$(BUILD_MODE)/%.o)
-USE_INTERNAL_LIBEVHTP ?= 1
-
-ifeq (1, $(USE_INTERNAL_LIBEVHTP))
-LIBEVHTP_INCLUDES = -Ithird_party/libevhtp -I$(dir $(third_party_libevhtp_header))
-LIBEVHTP_HEADERS = $(third_party_libevhtp_header)
-else
-LIBEVHTP_INCLUDES =
-LIBEVHTP_HEADERS =
-endif
-
$(examples_provider_obj_files) : $(LIBEVHTP_HEADERS)
$(examples_provider_obj_files) : INCLUDES += $(LIBEVHTP_INCLUDES)
$(examples_provider_obj_files) : out/$(BUILD_MODE)/%.o : %.cc
@@ -43,7 +33,7 @@ $(examples_daemon_obj_files) : out/$(BUILD_MODE)/%.o : %.cc
mkdir -p $(dir $@)
$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
-daemon_common_flags := \
+example_daemon_common_flags := \
-Wl,-rpath=out/$(BUILD_MODE)/ \
-levent \
-levent_openssl \
@@ -55,31 +45,31 @@ daemon_common_flags := \
-lssl \
-lcrypto
-daemon_deps := out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+example_daemon_deps := out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
ifeq (1, $(USE_INTERNAL_LIBEVHTP))
-daemon_deps += $(third_party_libevhtp_lib)
+example_daemon_deps += $(third_party_libevhtp_lib)
else
-daemon_common_flags += -levhtp
+example_daemon_common_flags += -levhtp
endif
-out/$(BUILD_MODE)/weave_daemon_ledflasher : out/$(BUILD_MODE)/examples/daemon/ledflasher/ledflasher.o $(daemon_deps)
- $(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
+out/$(BUILD_MODE)/weave_daemon_ledflasher : out/$(BUILD_MODE)/examples/daemon/ledflasher/ledflasher.o $(example_daemon_deps)
+ $(CXX) -o $@ $^ $(CFLAGS) $(example_daemon_common_flags)
-out/$(BUILD_MODE)/weave_daemon_light : out/$(BUILD_MODE)/examples/daemon/light/light.o $(daemon_deps)
- $(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
+out/$(BUILD_MODE)/weave_daemon_light : out/$(BUILD_MODE)/examples/daemon/light/light.o $(example_daemon_deps)
+ $(CXX) -o $@ $^ $(CFLAGS) $(example_daemon_common_flags)
-out/$(BUILD_MODE)/weave_daemon_lock : out/$(BUILD_MODE)/examples/daemon/lock/lock.o $(daemon_deps)
- $(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
+out/$(BUILD_MODE)/weave_daemon_lock : out/$(BUILD_MODE)/examples/daemon/lock/lock.o $(example_daemon_deps)
+ $(CXX) -o $@ $^ $(CFLAGS) $(example_daemon_common_flags)
-out/$(BUILD_MODE)/weave_daemon_oven : out/$(BUILD_MODE)/examples/daemon/oven/oven.o $(daemon_deps)
- $(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
+out/$(BUILD_MODE)/weave_daemon_oven : out/$(BUILD_MODE)/examples/daemon/oven/oven.o $(example_daemon_deps)
+ $(CXX) -o $@ $^ $(CFLAGS) $(example_daemon_common_flags)
-out/$(BUILD_MODE)/weave_daemon_sample : out/$(BUILD_MODE)/examples/daemon/sample/sample.o $(daemon_deps)
- $(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
+out/$(BUILD_MODE)/weave_daemon_sample : out/$(BUILD_MODE)/examples/daemon/sample/sample.o $(example_daemon_deps)
+ $(CXX) -o $@ $^ $(CFLAGS) $(example_daemon_common_flags)
-out/$(BUILD_MODE)/weave_daemon_speaker : out/$(BUILD_MODE)/examples/daemon/speaker/speaker.o $(daemon_deps)
- $(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
+out/$(BUILD_MODE)/weave_daemon_speaker : out/$(BUILD_MODE)/examples/daemon/speaker/speaker.o $(example_daemon_deps)
+ $(CXX) -o $@ $^ $(CFLAGS) $(example_daemon_common_flags)
all-examples : out/$(BUILD_MODE)/weave_daemon_ledflasher out/$(BUILD_MODE)/weave_daemon_light out/$(BUILD_MODE)/weave_daemon_lock out/$(BUILD_MODE)/weave_daemon_oven out/$(BUILD_MODE)/weave_daemon_sample out/$(BUILD_MODE)/weave_daemon_speaker
diff --git a/include/weave/device.h b/include/weave/device.h
index b79e6a3..5d455de 100644
--- a/include/weave/device.h
+++ b/include/weave/device.h
@@ -23,6 +23,25 @@
namespace weave {
+// This interface defines interactions with a Weave device. Implemented in
+// weave::DeviceManager. The general use of this class is to:
+// - Define the traits for the Weave schema the device is
+// interested in using the AddTraitDefinitions() and
+// AddTraitDefinitionsFromJson() functions.
+// - Define the components for the Weave schema the device is
+// interested in using the AddComponent() function.
+// - Set the initial/default values of "state" portions of the schema using
+// the SetStatePropertiesFromJson() and SetStateProperties() functions.
+// - Specify callback functions when a command (defined in the Weave schema)
+// is received by the device using the AddCommandHandler() function.
+//
+// A daemon will typically create one instance of a class implementing
+// Device and will retain it for the life of the daemon using the Create()
+// function.
+//
+// For detailed examples of the usage of this class, see the examples/daemon
+// directory.
+
// States of Gcd connection.
enum class GcdState {
kUnconfigured, // Device was not registered.
diff --git a/src/device_registration_info.cc b/src/device_registration_info.cc
index a278e63..195895f 100644
--- a/src/device_registration_info.cc
+++ b/src/device_registration_info.cc
@@ -46,7 +46,6 @@ namespace fetch_reason {
const char kDeviceStart[] = "device_start"; // Initial queue fetch at startup.
const char kRegularPull[] = "regular_pull"; // Regular fetch before XMPP is up.
const char kNewCommand[] = "new_command"; // A new command is available.
-const char kJustInCase[] = "just_in_case"; // Backup fetch when XMPP is live.
} // namespace fetch_reason
@@ -452,8 +451,17 @@ void DeviceRegistrationInfo::StartNotificationChannel() {
// Start with just regular polling at the pre-configured polling interval.
// Once the primary notification channel is connected successfully, it will
// call back to OnConnected() and at that time we'll switch to use the
- // primary channel and switch periodic poll into much more infrequent backup
- // poll mode.
+ // primary channel and turn off the periodic polling.
+ StartPullChannel();
+
+ notification_channel_starting_ = true;
+ primary_notification_channel_.reset(
+ new XmppChannel{GetSettings().robot_account, access_token_,
+ GetSettings().xmpp_endpoint, task_runner_, network_});
+ primary_notification_channel_->Start(this);
+}
+
+void DeviceRegistrationInfo::StartPullChannel() {
const base::TimeDelta pull_interval =
base::TimeDelta::FromSeconds(kPollingPeriodSeconds);
if (!pull_channel_) {
@@ -463,12 +471,12 @@ void DeviceRegistrationInfo::StartNotificationChannel() {
pull_channel_->UpdatePullInterval(pull_interval);
}
current_notification_channel_ = pull_channel_.get();
+}
- notification_channel_starting_ = true;
- primary_notification_channel_.reset(
- new XmppChannel{GetSettings().robot_account, access_token_,
- GetSettings().xmpp_endpoint, task_runner_, network_});
- primary_notification_channel_->Start(this);
+void DeviceRegistrationInfo::StopPullChannel() {
+ pull_channel_->Stop();
+ pull_channel_.reset();
+ current_notification_channel_ = nullptr;
}
void DeviceRegistrationInfo::AddGcdStateChangedCallback(
@@ -1278,8 +1286,7 @@ void DeviceRegistrationInfo::OnConnected(const std::string& channel_name) {
<< channel_name;
CHECK_EQ(primary_notification_channel_->GetName(), channel_name);
notification_channel_starting_ = false;
- pull_channel_->UpdatePullInterval(
- base::TimeDelta::FromMinutes(kBackupPollingPeriodMinutes));
+ StopPullChannel();
current_notification_channel_ = primary_notification_channel_.get();
// If we have not successfully connected to the cloud server and we have not
@@ -1304,9 +1311,8 @@ void DeviceRegistrationInfo::OnDisconnected() {
if (!HaveRegistrationCredentials() || !connected_to_cloud_)
return;
- pull_channel_->UpdatePullInterval(
- base::TimeDelta::FromSeconds(kPollingPeriodSeconds));
- current_notification_channel_ = pull_channel_.get();
+ // Restart polling.
+ StartPullChannel();
UpdateDeviceResource(base::Bind(&IgnoreCloudError));
}
@@ -1319,33 +1325,16 @@ void DeviceRegistrationInfo::OnPermanentFailure() {
void DeviceRegistrationInfo::OnCommandCreated(
const base::DictionaryValue& command,
- const std::string& channel_name) {
+ const std::string& /* channel_name */) {
if (!connected_to_cloud_)
return;
VLOG(1) << "Command notification received: " << command;
- if (!command.empty()) {
- // GCD spec indicates that the command parameter in notification object
- // "may be empty if command size is too big".
- PublishCommand(command);
- return;
- }
-
- // If this request comes from a Pull channel while the primary notification
- // channel (XMPP) is active, we are doing a backup poll, so mark the request
- // appropriately.
- bool just_in_case =
- (channel_name == kPullChannelName) &&
- (current_notification_channel_ == primary_notification_channel_.get());
-
- std::string reason =
- just_in_case ? fetch_reason::kJustInCase : fetch_reason::kNewCommand;
-
// If the command was too big to be delivered over a notification channel,
// or OnCommandCreated() was initiated from the Pull notification,
// perform a manual command fetch from the server here.
- FetchAndPublishCommands(reason);
+ FetchAndPublishCommands(fetch_reason::kNewCommand);
}
void DeviceRegistrationInfo::OnDeviceDeleted(const std::string& cloud_id) {
@@ -1378,10 +1367,7 @@ void DeviceRegistrationInfo::RemoveCredentials() {
primary_notification_channel_->Stop();
primary_notification_channel_.reset();
}
- if (pull_channel_) {
- pull_channel_->Stop();
- pull_channel_.reset();
- }
+ StopPullChannel();
notification_channel_starting_ = false;
SetGcdState(GcdState::kInvalidCredentials);
}
diff --git a/src/device_registration_info.h b/src/device_registration_info.h
index db08ef9..5ecdcac 100644
--- a/src/device_registration_info.h
+++ b/src/device_registration_info.h
@@ -161,6 +161,10 @@ class DeviceRegistrationInfo : public NotificationDelegate,
// restarted anytime the access_token is refreshed.
void StartNotificationChannel();
+ // Helpers to start and stop pull notification channel.
+ void StartPullChannel();
+ void StopPullChannel();
+
// Do a HTTPS request to cloud services.
// Handles many cases like reauthorization, 5xx HTTP response codes
// and device removal. It is a recommended way to do cloud API
diff --git a/tests.mk b/tests.mk
index c7db877..a02100b 100644
--- a/tests.mk
+++ b/tests.mk
@@ -64,6 +64,22 @@ export-test : out/$(BUILD_MODE)/libweave_exports_testrunner
$(TEST_ENV) $< $(TEST_FLAGS)
testall : test export-test
+check : testall
-.PHONY : test export-test testall
+###
+# coverage
+# This runs coverage against unit tests, invoke with "make coverage".
+# Output "homepage" is out/$(BUILD_MODE)/coverage_html/index.html
+# Running a mode other than Debug will result in incorrect coverage data.
+# https://gcc.gnu.org/onlinedocs/gcc/Gcov-and-Optimization.html
+
+coverage: CFLAGS+=--coverage
+
+run_coverage: test
+ lcov --capture --directory out/$(BUILD_MODE) --output-file out/$(BUILD_MODE)/coverage.info
+ lcov -b . --remove out/$(BUILD_MODE)/coverage.info "*third_party*" "/usr/include/*" "*/include/weave/test/*" "*/src/test/*" "*/include/weave/provider/test/*" -o out/$(BUILD_MODE)/coverage_filtered.info
+ genhtml out/$(BUILD_MODE)/coverage_filtered.info --output-directory out/$(BUILD_MODE)/coverage_html
+
+coverage: run_coverage
+.PHONY : check coverage run_coverage test export-test testall
diff --git a/tests_schema/daemon/testdevice/standard_traits.h b/tests_schema/daemon/testdevice/standard_traits.h
new file mode 100644
index 0000000..354c783
--- /dev/null
+++ b/tests_schema/daemon/testdevice/standard_traits.h
@@ -0,0 +1,216 @@
+// Copyright 2016 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.
+
+namespace standardtraits {
+const char kTraits[] = R"({
+ "lock": {
+ "commands": {
+ "setConfig": {
+ "minimalRole": "user",
+ "parameters": {
+ "lockedState": {
+ "type": "string",
+ "enum": [ "locked", "unlocked" ]
+ }
+ },
+ "errors": [ "jammed", "lockingNotSupported" ]
+ }
+ },
+ "state": {
+ "lockedState": {
+ "type": "string",
+ "enum": [ "locked", "unlocked", "partiallyLocked" ],
+ "isRequired": true
+ },
+ "isLockingSupported": {
+ "type": "boolean",
+ "isRequired": true
+ }
+ }
+ },
+ "onOff": {
+ "commands": {
+ "setConfig": {
+ "minimalRole": "user",
+ "parameters": {
+ "state": {
+ "type": "string",
+ "enum": [ "on", "off" ]
+ }
+ }
+ }
+ },
+ "state": {
+ "state": {
+ "type": "string",
+ "enum": [ "on", "off" ],
+ "isRequired": true
+ }
+ }
+ },
+ "brightness": {
+ "commands": {
+ "setConfig": {
+ "minimalRole": "user",
+ "parameters": {
+ "brightness": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ }
+ }
+ }
+ },
+ "state": {
+ "brightness": {
+ "isRequired": true,
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ }
+ }
+ },
+ "colorTemp": {
+ "commands": {
+ "setConfig": {
+ "minimalRole": "user",
+ "parameters": {
+ "colorTemp": {
+ "type": "integer"
+ }
+ }
+ }
+ },
+ "state": {
+ "colorTemp": {
+ "isRequired": true,
+ "type": "integer"
+ },
+ "minColorTemp": {
+ "isRequired": true,
+ "type": "integer"
+ },
+ "maxColorTemp": {
+ "isRequired": true,
+ "type": "integer"
+ }
+ }
+ },
+ "colorXy": {
+ "commands": {
+ "setConfig": {
+ "minimalRole": "user",
+ "parameters": {
+ "colorSetting": {
+ "type": "object",
+ "required": [
+ "colorX",
+ "colorY"
+ ],
+ "properties": {
+ "colorX": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ },
+ "colorY": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "errors": ["colorOutOfRange"]
+ }
+ },
+ "state": {
+ "colorSetting": {
+ "type": "object",
+ "isRequired": true,
+ "required": [ "colorX", "colorY" ],
+ "properties": {
+ "colorX": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ },
+ "colorY": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ }
+ }
+ },
+ "colorCapRed": {
+ "type": "object",
+ "isRequired": true,
+ "required": [ "colorX", "colorY" ],
+ "properties": {
+ "colorX": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ },
+ "colorY": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ }
+ }
+ },
+ "colorCapGreen": {
+ "type": "object",
+ "isRequired": true,
+ "required": [ "colorX", "colorY" ],
+ "properties": {
+ "colorX": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ },
+ "colorY": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ }
+ }
+ },
+ "colorCapBlue": {
+ "type": "object",
+ "isRequired": true,
+ "required": [ "colorX", "colorY" ],
+ "properties": {
+ "colorX": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ },
+ "colorY": {
+ "type": "number",
+ "minimum": 0.0,
+ "maximum": 1.0
+ }
+ }
+ }
+ }
+ }
+})";
+
+const char kDefaultState[] = R"({
+ "lock":{"isLockingSupported": true},
+ "onOff":{"state": "on"},
+ "brightness":{"brightness": 0.0},
+ "colorTemp":{"colorTemp": 0},
+ "colorXy": {
+ "colorSetting": {"colorX": 0.0, "colorY": 0.0},
+ "colorCapRed": {"colorX": 0.674, "colorY": 0.322},
+ "colorCapGreen":{"colorX": 0.408, "colorY": 0.517},
+ "colorCapBlue": {"colorX": 0.168, "colorY": 0.041}
+ }
+})";
+
+const char kComponent[] = "testdevice";
+} // namespace jsontraits
diff --git a/tests_schema/daemon/testdevice/testdevice.cc b/tests_schema/daemon/testdevice/testdevice.cc
new file mode 100644
index 0000000..7dea5ac
--- /dev/null
+++ b/tests_schema/daemon/testdevice/testdevice.cc
@@ -0,0 +1,277 @@
+// 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 <algorithm>
+#include <string>
+#include <typeinfo>
+
+#include "examples/daemon/common/daemon.h"
+#include "tests_schema/daemon/testdevice/standard_traits.h"
+
+#include <weave/device.h>
+#include <weave/enum_to_string.h>
+
+#include <base/bind.h>
+#include <base/memory/weak_ptr.h>
+
+namespace weave {
+namespace lockstate {
+enum class LockState { kUnlocked, kLocked, kPartiallyLocked };
+
+const weave::EnumToStringMap<LockState>::Map kLockMapMethod[] = {
+ {LockState::kLocked, "locked"},
+ {LockState::kUnlocked, "unlocked"},
+ {LockState::kPartiallyLocked, "partiallyLocked"}};
+} // namespace lockstate
+
+template <>
+EnumToStringMap<lockstate::LockState>::EnumToStringMap()
+ : EnumToStringMap(lockstate::kLockMapMethod) {}
+} // namespace weave
+
+// TestDeviceHandler is a command handler example that shows
+// how to handle commands for a Weave testdevice.
+class TestDeviceHandler {
+ public:
+ TestDeviceHandler() = default;
+ void Register(weave::Device* device) {
+ device_ = device;
+
+ device->AddTraitDefinitionsFromJson(standardtraits::kTraits);
+ CHECK(device->AddComponent(
+ standardtraits::kComponent,
+ {"lock", "onOff", "brightness", "colorTemp", "colorXy"}, nullptr));
+ CHECK(device->SetStatePropertiesFromJson(
+ standardtraits::kComponent, standardtraits::kDefaultState, nullptr));
+
+ UpdateTestDeviceState();
+
+ device->AddCommandHandler(standardtraits::kComponent, "onOff.setConfig",
+ base::Bind(&TestDeviceHandler::OnOnOffSetConfig,
+ weak_ptr_factory_.GetWeakPtr()));
+ device->AddCommandHandler(standardtraits::kComponent, "lock.setConfig",
+ base::Bind(&TestDeviceHandler::OnLockSetConfig,
+ weak_ptr_factory_.GetWeakPtr()));
+ device->AddCommandHandler(
+ standardtraits::kComponent, "brightness.setConfig",
+ base::Bind(&TestDeviceHandler::OnBrightnessSetConfig,
+ weak_ptr_factory_.GetWeakPtr()));
+ device->AddCommandHandler(
+ standardtraits::kComponent, "colorTemp.setConfig",
+ base::Bind(&TestDeviceHandler::OnColorTempSetConfig,
+ weak_ptr_factory_.GetWeakPtr()));
+ device->AddCommandHandler(standardtraits::kComponent, "colorXy.setConfig",
+ base::Bind(&TestDeviceHandler::OnColorXySetConfig,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ private:
+ void OnLockSetConfig(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 requested_state;
+ if (params.GetString("lockedState", &requested_state)) {
+ LOG(INFO) << cmd->GetName() << " state: " << requested_state;
+
+ weave::lockstate::LockState new_lock_status;
+
+ if (!weave::StringToEnum(requested_state, &new_lock_status)) {
+ // Invalid lock state was specified.
+ AbortCommand(cmd);
+ return;
+ }
+
+ if (new_lock_status != lock_state_) {
+ lock_state_ = new_lock_status;
+
+ LOG(INFO) << "Lock is now: " << requested_state;
+ UpdateTestDeviceState();
+ }
+ cmd->Complete({}, nullptr);
+ return;
+ }
+ AbortCommand(cmd);
+ }
+
+ void OnBrightnessSetConfig(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();
+ double brightness_value = 0.0;
+ if (params.GetDouble("brightness", &brightness_value)) {
+ LOG(INFO) << cmd->GetName() << " brightness: " << brightness_value;
+
+ if (brightness_value < 0.0 || brightness_value > 1.0) {
+ // Invalid brightness range value is specified.
+ AbortCommand(cmd);
+ return;
+ }
+
+ if (brightness_state_ != brightness_value) {
+ brightness_state_ = brightness_value;
+ UpdateTestDeviceState();
+ }
+ cmd->Complete({}, nullptr);
+ return;
+ }
+ AbortCommand(cmd);
+ }
+
+ void OnOnOffSetConfig(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 requested_state;
+ if (params.GetString("state", &requested_state)) {
+ LOG(INFO) << cmd->GetName() << " state: " << requested_state;
+
+ std::string temp_state = requested_state;
+ std::transform(temp_state.begin(), temp_state.end(), temp_state.begin(),
+ ::toupper);
+ if (temp_state != "ON" && temp_state != "OFF") {
+ // Invalid OnOff state is specified.
+ AbortCommand(cmd);
+ return;
+ }
+
+ bool new_light_status = requested_state == "on";
+ if (new_light_status != light_status_) {
+ light_status_ = new_light_status;
+ LOG(INFO) << "Light is now: " << (light_status_ ? "ON" : "OFF");
+ UpdateTestDeviceState();
+ }
+ cmd->Complete({}, nullptr);
+ return;
+ }
+ AbortCommand(cmd);
+ }
+
+ void OnColorTempSetConfig(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();
+ int32_t color_temp = 0;
+ if (params.GetInteger("colorTemp", &color_temp)) {
+ LOG(INFO) << cmd->GetName() << " colorTemp: " << color_temp;
+
+ if (color_temp < 0.0 || color_temp > 1.0) {
+ // Invalid color_temp value is specified.
+ AbortCommand(cmd);
+ return;
+ }
+
+ if (color_temp != color_temp_) {
+ color_temp_ = color_temp;
+
+ LOG(INFO) << "color_Temp is now: " << color_temp_;
+ UpdateTestDeviceState();
+ }
+ cmd->Complete({}, nullptr);
+ return;
+ }
+
+ AbortCommand(cmd);
+ }
+
+ void OnColorXySetConfig(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();
+ const base::DictionaryValue* colorXy = nullptr;
+ if (params.GetDictionary("colorSetting", &colorXy)) {
+ bool updateState = false;
+ double X = 0.0;
+ double Y = 0.0;
+ if (colorXy->GetDouble("colorX", &X)) {
+ color_X_ = X;
+ updateState = true;
+ }
+
+ if (colorXy->GetDouble("colorY", &Y)) {
+ color_Y_ = Y;
+ updateState = true;
+ }
+
+ if ((color_X_ < 0.0 || color_Y_ > 1.0) ||
+ (color_Y_ < 0.0 || color_Y_ > 1.0)) {
+ // Invalid color range value is specified.
+ AbortCommand(cmd);
+ return;
+ }
+
+ if (updateState)
+ UpdateTestDeviceState();
+
+ cmd->Complete({}, nullptr);
+ return;
+ }
+
+ AbortCommand(cmd);
+ }
+
+ void UpdateTestDeviceState() {
+ std::string updated_state = weave::EnumToString(lock_state_);
+ device_->SetStateProperty(standardtraits::kComponent, "lock.lockedState",
+ base::StringValue{updated_state}, nullptr);
+ base::DictionaryValue state;
+ state.SetString("onOff.state", light_status_ ? "on" : "off");
+ state.SetDouble("brightness.brightness", brightness_state_);
+ state.SetInteger("colorTemp.minColorTemp", color_temp_min_value_);
+ state.SetInteger("colorTemp.maxColorTemp", color_temp_max_value_);
+ state.SetInteger("colorTemp.colorTemp", color_temp_);
+
+ std::unique_ptr<base::DictionaryValue> colorXy(new base::DictionaryValue());
+ colorXy->SetDouble("colorX", color_X_);
+ colorXy->SetDouble("colorY", color_Y_);
+ state.Set("colorXy.colorSetting", std::move(colorXy));
+
+ device_->SetStateProperties(standardtraits::kComponent, state, nullptr);
+ }
+
+ void AbortCommand(std::shared_ptr<weave::Command>& cmd) {
+ weave::ErrorPtr error;
+ weave::Error::AddTo(&error, FROM_HERE, "invalidParameterValue",
+ "Invalid parameters");
+ cmd->Abort(error.get(), nullptr);
+ }
+
+ weave::Device* device_{nullptr};
+
+ // Simulate the state of the testdevice.
+ weave::lockstate::LockState lock_state_{weave::lockstate::LockState::kLocked};
+ bool light_status_{false};
+ double brightness_state_{0.0};
+ int32_t color_temp_{0};
+ int32_t color_temp_min_value_{0};
+ int32_t color_temp_max_value_{1};
+ double color_X_{0.0};
+ double color_Y_{0.0};
+ base::WeakPtrFactory<TestDeviceHandler> weak_ptr_factory_{this};
+};
+
+int main(int argc, char** argv) {
+ Daemon::Options opts;
+ opts.model_id = "AOAAA";
+ if (!opts.Parse(argc, argv)) {
+ Daemon::Options::ShowUsage(argv[0]);
+ return 1;
+ }
+ Daemon daemon{opts};
+ TestDeviceHandler handler;
+ handler.Register(daemon.GetDevice());
+ daemon.Run();
+ return 0;
+}
diff --git a/tests_schema/tests_schema.mk b/tests_schema/tests_schema.mk
new file mode 100644
index 0000000..73dfefd
--- /dev/null
+++ b/tests_schema/tests_schema.mk
@@ -0,0 +1,45 @@
+# Copyright 2016 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.
+
+###
+# test_schema
+
+TESTS_SCHEMA_DAEMON_SRC_FILES := \
+ tests_schema/daemon/testdevice/testdevice.cc
+
+tests_schema_daemon_obj_files := $(TESTS_SCHEMA_DAEMON_SRC_FILES:%.cc=out/$(BUILD_MODE)/%.o)
+
+$(tests_schema_daemon_obj_files) : $(LIBEVHTP_HEADERS)
+$(tests_schema_daemon_obj_files) : INCLUDES += $(LIBEVHTP_INCLUDES)
+$(tests_schema_daemon_obj_files) : out/$(BUILD_MODE)/%.o : %.cc
+ mkdir -p $(dir $@)
+ $(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
+
+tests_schema_daemon_common_flags := \
+ -Wl,-rpath=out/$(BUILD_MODE)/ \
+ -levent \
+ -levent_openssl \
+ -lpthread \
+ -lavahi-common \
+ -lavahi-client \
+ -lexpat \
+ -lcurl \
+ -lssl \
+ -lcrypto
+
+tests_schema_daemon_deps := out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+
+ifeq (1, $(USE_INTERNAL_LIBEVHTP))
+tests_schema_daemon_deps += $(third_party_libevhtp_lib)
+else
+tests_schema_daemon_common_flags += -levhtp
+endif
+
+out/$(BUILD_MODE)/weave_daemon_testdevice : out/$(BUILD_MODE)/tests_schema/daemon/testdevice/testdevice.o $(tests_schema_daemon_deps)
+ $(CXX) -o $@ $^ $(CFLAGS) $(tests_schema_daemon_common_flags)
+
+all-testdevices : out/$(BUILD_MODE)/weave_daemon_testdevice
+
+.PHONY : all-testdevices
+
diff --git a/third_party/third_party.mk b/third_party/third_party.mk
index 18f9b98..e1da63c 100644
--- a/third_party/third_party.mk
+++ b/third_party/third_party.mk
@@ -94,3 +94,14 @@ $(third_party_libevhtp_lib) : $(third_party_libevhtp_header)
clean-libevhtp :
rm -rf $(third_party_libevhtp)
+
+# These settings are exported for other code to use as needed.
+USE_INTERNAL_LIBEVHTP ?= 1
+
+ifeq (1, $(USE_INTERNAL_LIBEVHTP))
+LIBEVHTP_INCLUDES = -Ithird_party/libevhtp -I$(dir $(third_party_libevhtp_header))
+LIBEVHTP_HEADERS = $(third_party_libevhtp_header)
+else
+LIBEVHTP_INCLUDES =
+LIBEVHTP_HEADERS =
+endif