DeviceConnectを用いたHueランプの操作

# はじめに

DeviceConnect APIを用いてHueランプを操作できるwebアプリを開発しました。カラーピッカーをクリックすることで好きな色にHueを点灯させることができます。
DeviceConect APIはNTTドコモが開発しているAPIです。
今回はJavaScriptで開発を行います。

## 使用するデバイス

- Android端末（Androidバージョン6.0.1）
- Philips Hue

## Device Web API Managerのインストール

- まずサーバとなるスマートフォンにgclue社のDevice Web API Managerをインストールします。
- 使いたいIoTデバイスのプラグインをスマートフォンにインスト―ルします。

今回はHueプラグインを利用します。

## JavaScriptでDeviceConnectを利用するための準備

### DeviceConnectのJavaScript用SDKのダウンロード

https://github.com/DeviceConnect/DeviceConnect-JS にあるSDKをダウンロードします。
現時点で最新のバージョン2.2.0をダウンロードします。
curlでダウンロードする際は以下のコマンドを使用してください。

```
$ curl https://raw.githubusercontent.com/DeviceConnect/DeviceConnect-JS/master/dConnectSDKForJavascript/dconnectsdk-2.2.0.js -O
```

### DeviceConnectサーバのIPアドレスを確認

DeviceConnectサーバのIPアドレスを確認します。DeviceConnectサーバのIPアドレスはDevice Web API Managerアプリの設定で確認できます。

<img alt="IP確認" src="https://qiita-image-store.s3.amazonaws.com/0/254347/2f7358e4-13c7-c114-f628-37cc039af8f9.png" width="300" >






## 開発

### DeviceConnectのセットアップ
DeviceConnectを使うためのひな型は[DeviceConnect Users](https://deviceconnectusers.github.io/)や[DeviceConnect](https://github.com/DeviceConnect)を参考に作成しています。DeviceConnectサーバのIPアドレスとHueランプの名前は各自の環境に合わせ、変更してください。
HTMLファイルでSDKとjQueryを読み込んでください。

### カラーピッカー

カラーピッカーは[Farbtastic Color Picker](http://acko.net/blog/farbtastic-jquery-color-picker-plug-in/)で実現します。

### イベントの間引き

Hueの色を変えるためのリクエストを短期間で送り続けるとエラーが発生してしまいます。そこで発生するイベントをlodashの[throttle関数](https://lodash.com/docs/#throttle)で間引きします。

### ソースコード

#### HTML

```html:index.html
<!DOCTYPE html>
<html>
<head>
  <title>Hue color</title>
  <meta charset="utf-8">
  <link rel="stylesheet" href="./css/farbtastic.css" type="text/css" />
  <!-- DeviceConnectのJavaScript用SDK -->
  <script src="./js/sdk/dconnectsdk-2.2.0.js" type="text/javascript"></script>
  <script  src="https://code.jquery.com/jquery-3.3.1.js"  integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="  crossorigin="anonymous"></script>
  <!-- カラーピッカー -->
  <script src="./js/farbtastic.js" type="text/javascript"></script>
  <!-- lodash イベント間引き用 -->
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
  <script src="./js/app.js" type="text/javascript"></script>
</head>
<body>
  <p>
    <button id="getStatus">DeviceConnectセットアップ</button>
  </p>
  <p>
    <!-- DeviceConnectサーバのIPアドレス -->
    <input type="text" value="xxx.xxx.xxx.xxx" id="server" placeholder="DeviceConnectサーバのIPアドレス" />
  </p>
  <div id="checkDeviceConnect"></div>
  <h2>hueランプ操作</h2>
  <div>
    WebColor:<output id="webcolor">#000000</output>
  </div>
  <div id="picker"></div>
  <div>
    <input type="button" value="消灯" id="offhue">
  </div>
</body>
</html>
```


#### JavaScript

```js:app.js
const app = {
  scopes:Array("battery", "connect", "deviceorientation",
  "file", "mediaPlayer", "mediastreamRecording",
  "notification", "phone", "proximity", "settings",
  "vibration", "serviceinformation", "servicediscovery",
  "illuminance", "touch", "light"
),
applicationName: "myApp",
sessionKey: null
}

// 認可を得る
const getAuthentication = () => {
  dConnect.authorization(app.scopes, app.applicationName, (clientId, accessToken) => {
    // 許可が得られた場合
    app.accessToken = accessToken;
    getServices(accessToken);
    // WebSocketを開く場合、コメントアウトを外す
    // dConnect.connectWebSocket(accessToken, (eventCode, message) => {
    //   console.log(eventCode + ", " + message);
    // });
  }, (errorCode, errorMessage) => {
    // 許可が得られなかった場合
    console.error(errorMessage);
  });
};

// 認証を得る
const getServices = (accessToken) => {
  dConnect.discoverDevices(accessToken, (json) => {
    console.log("json",json);
    app.services = json.services;
  }, (errorCode, errorMessage) => {
    // 認証が得られなかった場合
    console.error(errorMessage);
  });
};

// hueをoffにする
const offHue = () => {
  const service = app.services.filter((s) => {return s.name == "hueの名前"})[0];
  const builder = new dConnect.URIBuilder();
  builder.setProfile("light");
  builder.setServiceId(service.id);
  builder.setAccessToken(app.accessToken);
  dConnect.removeEventListener(builder.build(),
  (json) => {
    console.log("Success");
  }, (errorCode, errorMessage) => {
    console.log("Failed");
  });
};

// hueを点灯させる
const hueColor = (huecolor) => {
  const service = app.services.filter((s) => {return s.name == "hueの名前"})[0];
  const builder = new dConnect.URIBuilder();
  builder.setProfile("light");
  builder.setServiceId(service.id);
  builder.setAccessToken(app.accessToken);
  // webカラーの'#'を取り除く
  builder.addParameter("color", huecolor.slice( -6 ));
  dConnect.post(builder.build(), null, null,
  (json) => {
    console.log("success");
  }, (errorCode, errorMessage) => {
    console.log("Failed");
  });
};


$(function() {
  // DeviceConnectセットアップ
  $("#getStatus").on("click", (e) => {
    dConnect.setHost($("#server").val());
    dConnect.checkDeviceConnect(
      (apiVersion) => {
        // 動作している場合
        $("#checkDeviceConnect").text("動作中");
        getAuthentication();
      }, (errorCode, errorMessage) => {
        // 動作していない場合
        $("#checkDeviceConnect").text(errorMessage);
      });
    });

    // hueを消す
    $("#offhue").on("click", (e) => {
      e.preventDefault();
      offHue();
    });

    // カラーピッカー
    $(document).ready(() => {
      $('#picker').farbtastic(_.throttle((c) => {
        // webcolorの値を表示する
        $('#webcolor').val(c)
        hueColor(c);
      }, 500));
    });
  });
```

## 動作

実際に動作させると次のようになります。

### webcolorを#1e060cにしたとき

<img alt="webcolor#1e060c" src="https://qiita-image-store.s3.amazonaws.com/0/254347/79392c35-1a21-0de3-a953-77cdf7589e63.png" width="600" >


### webcolorを#0802e6にしたとき

<img alt="webcolor#0802e6" src="https://qiita-image-store.s3.amazonaws.com/0/254347/dd1fa9f6-1a18-593a-1e01-28c420e952da.png" width="600" >

カラーピッカーをクリックすることでHueランプの色を変化させることができました。

## 参考
- [DeviceConnect Users](https://deviceconnectusers.github.io/)
- [DeviceConnect](https://github.com/DeviceConnect)