1// Copyright 2015 The Weave Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "examples/daemon/common/daemon.h"
6
7#include <weave/device.h>
8
9#include <base/bind.h>
10#include <base/memory/weak_ptr.h>
11
12namespace {
13
14const char kTraits[] = R"({
15  "onOff": {
16    "commands": {
17      "setConfig": {
18        "minimalRole": "user",
19        "parameters": {
20          "state": {
21            "type": "string",
22            "enum": [ "on", "standby" ]
23          }
24        }
25      }
26    },
27    "state": {
28      "state": {
29        "type": "string",
30        "enum": [ "on", "standby" ],
31        "isRequired": true
32      }
33    }
34  },
35  "volume": {
36    "commands": {
37      "setConfig": {
38        "minimalRole": "user",
39        "parameters": {
40          "volume": {
41            "type": "integer",
42            "minimum": 0,
43            "maximum": 100
44          },
45          "isMuted": { "type": "boolean" }
46        }
47      }
48    },
49    "state": {
50      "isMuted": {
51        "type": "boolean",
52        "isRequired": true
53      },
54      "volume": {
55        "type": "integer",
56        "minimum": 0,
57        "maximum": 100,
58        "isRequired": true
59      }
60    }
61  }
62})";
63
64const char kComponent[] = "speaker";
65
66}  // anonymous namespace
67
68// SpeakerHandler is a command handler example that shows
69// how to handle commands for a Weave speaker.
70class SpeakerHandler {
71 public:
72  SpeakerHandler() = default;
73  void Register(weave::Device* device) {
74    device_ = device;
75
76    device->AddTraitDefinitionsFromJson(kTraits);
77    CHECK(device->AddComponent(kComponent, {"onOff", "volume"}, nullptr));
78    UpdateSpeakerState();
79
80    device->AddCommandHandler(kComponent, "onOff.setConfig",
81                              base::Bind(&SpeakerHandler::OnOnOffSetConfig,
82                                         weak_ptr_factory_.GetWeakPtr()));
83    device->AddCommandHandler(kComponent, "volume.setConfig",
84                              base::Bind(&SpeakerHandler::OnVolumeSetConfig,
85                                         weak_ptr_factory_.GetWeakPtr()));
86  }
87
88 private:
89  void OnVolumeSetConfig(const std::weak_ptr<weave::Command>& command) {
90    auto cmd = command.lock();
91    if (!cmd)
92      return;
93    LOG(INFO) << "received command: " << cmd->GetName();
94
95    const auto& params = cmd->GetParameters();
96    // Handle volume parameter
97    int32_t volume_value = 0;
98    if (params.GetInteger("volume", &volume_value)) {
99      // Display this command in terminal.
100      LOG(INFO) << cmd->GetName() << " volume: " << volume_value;
101
102      if (volume_value_ != volume_value) {
103        volume_value_ = volume_value;
104        UpdateSpeakerState();
105      }
106      cmd->Complete({}, nullptr);
107      return;
108    }
109
110    // Handle isMuted parameter
111    bool isMuted_status = false;
112    if (params.GetBoolean("isMuted", &isMuted_status)) {
113      // Display this command in terminal.
114      LOG(INFO) << cmd->GetName() << " is "
115                << (isMuted_status ? "muted" : "not muted");
116
117      if (isMuted_status_ != isMuted_status) {
118        isMuted_status_ = isMuted_status;
119
120        LOG(INFO) << "Speaker is now: "
121                  << (isMuted_status ? "muted" : "not muted");
122        UpdateSpeakerState();
123      }
124    }
125
126    cmd->Complete({}, nullptr);
127  }
128
129  void OnOnOffSetConfig(const std::weak_ptr<weave::Command>& command) {
130    auto cmd = command.lock();
131    if (!cmd)
132      return;
133    LOG(INFO) << "received command: " << cmd->GetName();
134    const auto& params = cmd->GetParameters();
135    std::string requested_state;
136    if (params.GetString("state", &requested_state)) {
137      LOG(INFO) << cmd->GetName() << " state: " << requested_state;
138
139      bool new_speaker_status = requested_state == "on";
140      if (new_speaker_status != speaker_status_) {
141        speaker_status_ = new_speaker_status;
142
143        LOG(INFO) << "Speaker is now: " << (speaker_status_ ? "ON" : "OFF");
144        UpdateSpeakerState();
145      }
146    }
147    cmd->Complete({}, nullptr);
148  }
149
150  void UpdateSpeakerState() {
151    base::DictionaryValue state;
152    state.SetString("onOff.state", speaker_status_ ? "on" : "standby");
153    state.SetBoolean("volume.isMuted", isMuted_status_);
154    state.SetInteger("volume.volume", volume_value_);
155    device_->SetStateProperties(kComponent, state, nullptr);
156  }
157
158  weave::Device* device_{nullptr};
159
160  // Simulate the state of the speaker.
161  bool speaker_status_;
162  bool isMuted_status_;
163  int32_t volume_value_;
164  base::WeakPtrFactory<SpeakerHandler> weak_ptr_factory_{this};
165};
166
167int main(int argc, char** argv) {
168  Daemon::Options opts;
169  if (!opts.Parse(argc, argv)) {
170    Daemon::Options::ShowUsage(argv[0]);
171    return 1;
172  }
173  Daemon daemon{opts};
174  SpeakerHandler speaker;
175  speaker.Register(daemon.GetDevice());
176  daemon.Run();
177  return 0;
178}
179