Adding handler for speaker device.

Change-Id: Iff9ae5edc586e6f7e4820e825cc1d0d6ee2202eb
Reviewed-on: https://weave-review.googlesource.com/1471
Reviewed-by: Vitaly Buka <vitalybuka@google.com>
diff --git a/examples/daemon/examples.gyp b/examples/daemon/examples.gyp
index 8fee90d..2b497a5 100644
--- a/examples/daemon/examples.gyp
+++ b/examples/daemon/examples.gyp
@@ -7,7 +7,8 @@
         'sample/daemon.gyp:weave_daemon_sample',
         'light/daemon.gyp:weave_daemon_light',
         'lock/daemon.gyp:weave_daemon_lock',
-        'ledflasher/daemon.gyp:weave_daemon_ledflasher'
+        'ledflasher/daemon.gyp:weave_daemon_ledflasher',
+        'speaker/daemon.gyp:weave_daemon_speaker'
       ]
     }
   ]
diff --git a/examples/daemon/speaker/daemon.gyp b/examples/daemon/speaker/daemon.gyp
new file mode 100644
index 0000000..3bf7a91
--- /dev/null
+++ b/examples/daemon/speaker/daemon.gyp
@@ -0,0 +1,18 @@
+# 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.
+{
+  'targets': [
+    {
+      'target_name': 'weave_daemon_speaker',
+      'type': 'executable',
+      'sources': [
+        'speaker.cc',
+      ],
+      'dependencies': [
+        '<@(DEPTH)/libweave_standalone.gyp:libweave',
+        '<@(DEPTH)/examples/provider/provider.gyp:libweave_provider',
+      ]
+    }
+  ]
+}
diff --git a/examples/daemon/speaker/speaker.cc b/examples/daemon/speaker/speaker.cc
new file mode 100644
index 0000000..31a81a8
--- /dev/null
+++ b/examples/daemon/speaker/speaker.cc
@@ -0,0 +1,154 @@
+// 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 <base/bind.h>
+#include <base/memory/weak_ptr.h>
+
+// SpeakerHandler is a command handler example that shows
+// how to handle commands for a Weave speaker.
+class SpeakerHandler {
+ public:
+  SpeakerHandler() = default;
+  void Register(weave::Device* device) {
+    device_ = device;
+
+    device->AddStateDefinitionsFromJson(R"({
+      "onOff": {"state": ["on", "standby"]},
+      "volume": {
+        "volume": "integer",
+        "isMuted": "boolean"
+      }
+    })");
+
+    device->SetStatePropertiesFromJson(R"({
+      "onOff":{"state": "standby"},
+      "volume":{
+        "volume": 100,
+        "isMuted": false
+      }
+    })",
+                                       nullptr);
+
+    device->AddCommandDefinitionsFromJson(R"({
+      "onOff": {
+         "setConfig":{
+           "parameters": {
+             "state": ["on", "standby"]
+           }
+         }
+       },
+       "volume": {
+         "setConfig":{
+           "parameters": {
+             "volume": {
+               "type": "integer",
+               "minimum": 0,
+               "maximum": 100
+             },
+             "isMuted": "boolean"
+           }
+        }
+      }
+    })");
+    device->AddCommandHandler("onOff.setConfig",
+                              base::Bind(&SpeakerHandler::OnOnOffSetConfig,
+                                         weak_ptr_factory_.GetWeakPtr()));
+    device->AddCommandHandler("volume.setConfig",
+                              base::Bind(&SpeakerHandler::OnVolumeSetConfig,
+                                         weak_ptr_factory_.GetWeakPtr()));
+  }
+
+ private:
+  void OnVolumeSetConfig(const std::weak_ptr<weave::Command>& command) {
+    auto cmd = command.lock();
+    if (!cmd)
+      return;
+    LOG(INFO) << "received command: " << cmd->GetName();
+
+    // Handle volume parameter
+    int32_t volume_value = 0;
+    if (cmd->GetParameters()->GetInteger("volume", &volume_value)) {
+      // Display this command in terminal.
+      LOG(INFO) << cmd->GetName() << " volume: " << volume_value;
+
+      if (volume_value_ != volume_value) {
+        volume_value_ = volume_value;
+        UpdateSpeakerState();
+      }
+      cmd->Complete({}, nullptr);
+      return;
+    }
+
+    // Handle isMuted parameter
+    bool isMuted_status = false;
+    if (cmd->GetParameters()->GetBoolean("isMuted", &isMuted_status)) {
+      // Display this command in terminal.
+      LOG(INFO) << cmd->GetName() << " is " 
+                << (isMuted_status ? "muted" : "not muted");
+
+      if (isMuted_status_ != isMuted_status) {
+        isMuted_status_ = isMuted_status;
+
+        LOG(INFO) << "Speaker is now: " 
+                  << (isMuted_status ? "muted" : "not muted");
+        UpdateSpeakerState();
+      }
+    }
+
+    cmd->Complete({}, nullptr);
+  }
+
+  void OnOnOffSetConfig(const std::weak_ptr<weave::Command>& command) {
+    auto cmd = command.lock();
+    if (!cmd)
+      return;
+    LOG(INFO) << "received command: " << cmd->GetName();
+    std::string requested_state;
+    if (cmd->GetParameters()->GetString("state", &requested_state)) {
+      LOG(INFO) << cmd->GetName() << " state: " << requested_state;
+
+      bool new_speaker_status = requested_state == "on";
+      if (new_speaker_status != speaker_status_) {
+        speaker_status_ = new_speaker_status;
+
+        LOG(INFO) << "Speaker is now: " << (speaker_status_ ? "ON" : "OFF");
+        UpdateSpeakerState();
+      }
+    }
+    cmd->Complete({}, nullptr);
+  }
+
+  void UpdateSpeakerState() {
+    base::DictionaryValue state;
+    state.SetString("onOff.state", speaker_status_ ? "on" : "standby");
+    state.SetBoolean("volume.isMuted", isMuted_status_);
+    state.SetInteger("volume.volume", volume_value_);
+    device_->SetStateProperties(state, nullptr);
+  }
+
+  weave::Device* device_{nullptr};
+
+  // Simulate the state of the speaker.
+  bool speaker_status_;
+  bool isMuted_status_;
+  int32_t volume_value_;
+  base::WeakPtrFactory<SpeakerHandler> 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};
+  SpeakerHandler speaker;
+  speaker.Register(daemon.GetDevice());
+  daemon.Run();
+  return 0;
+}