diff options
author | Alex Vakulenko <avakulenko@google.com> | 2016-04-07 18:45:14 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-04-07 18:45:14 +0000 |
commit | 42e265469608501a577f0125cc10b20597dc23d5 (patch) | |
tree | fcb8970cd393990638c604abd533856dc9a914bb | |
parent | c76ba0bda5cd40af263467cc1ecdac0c537f914a (diff) | |
parent | 1ce13aa8c408baee70fac6bd1b0f19ec2db1bfc7 (diff) | |
download | libweave-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-- | Makefile | 9 | ||||
-rw-r--r-- | README.md | 23 | ||||
-rw-r--r-- | examples/examples.mk | 42 | ||||
-rw-r--r-- | include/weave/device.h | 19 | ||||
-rw-r--r-- | src/device_registration_info.cc | 58 | ||||
-rw-r--r-- | src/device_registration_info.h | 4 | ||||
-rw-r--r-- | tests.mk | 18 | ||||
-rw-r--r-- | tests_schema/daemon/testdevice/standard_traits.h | 216 | ||||
-rw-r--r-- | tests_schema/daemon/testdevice/testdevice.cc | 277 | ||||
-rw-r--r-- | tests_schema/tests_schema.mk | 45 | ||||
-rw-r--r-- | third_party/third_party.mk | 11 |
11 files changed, 657 insertions, 65 deletions
@@ -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 @@ -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 @@ -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 |